Compare commits

..

333 Commits

Author SHA1 Message Date
ilyaigpetrov
d86cf384af Bump 0.0.1.66 2024-07-30 15:39:06 +05:00
ilyaigpetrov
e1c95a3ece Add exact versions for reviewers 2024-07-30 15:38:19 +05:00
ilyaigpetrov
edabf14dd5 Add reference about why have to ask for consent 2024-07-15 23:41:37 +05:00
ilyaigpetrov
2f5d425f34 Autoclose the consent screen after user choice. Show consent screen only in FireFox 2024-07-15 23:40:31 +05:00
ilyaigpetrov
1c38137200
Remove the text about Mozilla ban 2024-06-15 11:57:19 +05:00
ilyaigpetrov
99b68ec8d0
Add a link to releases page for FireFox 2024-06-11 21:54:40 +05:00
ilyaigpetrov
0cc47d43a9
Mention that Mozilla blocks access for Russian IPs 2024-06-09 21:03:15 +05:00
Polycarbohydrate
a583e5ecb3 Fix English grammatical errors and add a translation. Merge PR #244
* Update README.md

* Fix minor punctuation mistakes

* Fix articles and other minor grammar mistakes

* Fix minor spelling mistakes

---------

Co-authored-by: ilyaigpetrov <ilyaigpetrov@gmail.com>
2024-05-13 21:17:41 +05:00
ilyaigpetrov
884b4f0fbc Fix spelling mistakes 2024-05-13 18:23:28 +05:00
ilyaigpetrov
770c4ab47d Bump 0.0.1.65 2024-05-13 18:22:24 +05:00
ilyaigpetrov
c5d9ca3254 Bump 0.0.1.64 2024-04-24 20:27:34 +05:00
ilyaigpetrov
27ad6944e0 Add consent screen 2024-04-24 20:15:14 +05:00
ilyaigpetrov
a589568bf9 Fix obsolete button title 2024-04-24 20:12:36 +05:00
ilyaigpetrov
b3585293a7 Replace the expired antizapret.info with rublacklist/roskomsvoboda registry of blocked sites 2024-03-29 22:25:22 +05:00
ilyaigpetrov
fd45db7dcc Rename the file for reviwers 2024-03-29 22:25:22 +05:00
ilyaigpetrov
65eb930682 Update AntiZapret urls 2024-03-29 22:25:22 +05:00
ilyaigpetrov
d3156175d8 Remove remnants of rebrand.ly shortened urls 2024-03-29 22:25:22 +05:00
ilyaigpetrov
c0862ecfff Bump 0.0.1.63 2024-03-29 22:25:22 +05:00
ilyaigpetrov
75d30ba467 Bump 0.0.1.62 2023-05-05 19:19:31 +05:00
ilyaigpetrov
a7e93d8383 Bump 0.0.1.61 2023-05-05 19:00:22 +05:00
ilyaigpetrov
b3096c8d83 Fix buggy update logic 2023-05-05 18:39:21 +05:00
ilyaigpetrov
ae930da8b3 Get rid of rebrand.ly everywhere in the code 2023-05-05 00:07:37 +05:00
ilyaigpetrov
451691ef2a Upgrade webpack 2023-05-04 23:37:28 +05:00
ilyaigpetrov
6e8943ca1c Bump 0.0.1.60 2023-04-26 05:31:12 +05:00
ilyaigpetrov
61f22e08be Replace 2 shortened links to resolved versions 2023-04-26 05:30:34 +05:00
ilyaigpetrov
b45a78e654 Bump 0.0.1.59 2023-04-26 05:25:17 +05:00
ilyaigpetrov
08e1b41780 Add another source for AntiZapret. Add AZ proxy for twitter to block-informer. Replace some rebrand.ly links (blocked on TSPU) 2023-04-26 05:16:43 +05:00
ilyaigpetrov
e5fb9d11dd Bump 0.0.1.58 2023-04-26 05:13:56 +05:00
ilyaigpetrov
689f9266f7 Add one more source for AntiZapret. Delete old update code. Move notes for reviewers from README to a separate file 2023-04-25 22:59:20 +05:00
ilyaigpetrov
6858c56534 Revert "Add Alt+P hotkey stub"
This reverts commit 3d72acc6dd.
2023-04-11 19:56:44 +05:00
ilyaigpetrov
7f9fb4f972
Update README.md 2022-10-02 18:45:41 +05:00
ilyaigpetrov
0e803bd08f
Replace some rebrandly links with direct links 2022-09-15 18:34:45 +05:00
ilyaigpetrov
6ef5807971
Add a link to the issue with alternative install methods (the default one is blocked for WebStore) 2022-09-14 16:21:53 +00:00
ilyaigpetrov
97adb7f3f4
Remove a maxim and a belief under "Why I do this" 2022-06-25 14:41:08 +00:00
ilyaigpetrov
db8dfbfd50
Remove Open Collective from GitHub FUNDING 2022-05-19 20:22:36 +05:00
ilyaigpetrov
3d72acc6dd Add Alt+P hotkey stub 2022-03-09 21:43:08 +05:00
ilyaigpetrov
0d7678ff50 Bump 0.0.1.57 2022-03-09 20:32:01 +05:00
ilyaigpetrov
edf6fc8b5f
Update README.md 2022-02-19 19:56:30 +05:00
ilyaigpetrov
0951e83dd1
Update README.md 2022-02-13 13:08:58 +00:00
ilyaigpetrov
79049bed25
Update README.md 2022-02-13 13:08:27 +00:00
ilyaigpetrov
951a5e9248 Update some deps for better security 2021-11-28 13:25:51 +00:00
ilyaigpetrov
6634f72580 Bump 0.0.1.56 2021-11-08 16:20:23 +00:00
ilyaigpetrov
aac0182738 Restrict min version for FireFox. r/ /%20/g in an url. Add link to the generator to README 2021-11-08 16:19:44 +00:00
ilyaigpetrov
8f00516d44 Merge branch 'work-even-if-dns-fails' into development 2021-09-15 16:30:18 +00:00
ilyaigpetrov
1265a3ad79 Bump 0.0.1.55 2021-09-15 16:29:37 +00:00
ilyaigpetrov
93aa084de9 Fix the bug with non-descriptive warnings. Make DNS errors non-critical 2021-09-15 16:27:23 +00:00
ilyaigpetrov
cb0d991e94 A fix for yandex browser(startsWith applied to undefined) 2021-09-12 09:03:49 +00:00
ilyaigpetrov
b77be60946 Trying to trace bug with non-descriptive warnings 2021-09-12 07:41:15 +00:00
ilyaigpetrov
1aec32de3e Add backup url for antizapret pac-script 2021-08-31 15:58:16 +00:00
ilyaigpetrov
86d07b79c3 make extension robust to dns failures (test0) 2021-08-27 16:19:50 +00:00
ilyaigpetrov
5b3e6f1f51 Break dns url for testing, don't fail on dns failure
In this commit all dns errors a swallowed during install
2021-08-27 15:28:03 +00:00
ilyaigpetrov
ce22337928 Bump 0.0.1.54 2021-08-27 14:06:11 +00:00
ilyaigpetrov
c0e5609d44 Give WARP SOCKS5 priority, WARP HTTPS doens't work in FireFox 2021-07-01 09:06:13 +00:00
ilyaigpetrov
c496fe1030 Merge branch 'development' of github.com:anticensority/runet-censorship-bypass into development 2021-07-01 08:36:58 +00:00
ilyaigpetrov
034c08828f Inform FireFox user about WARP proxying via block-informer (https proxy fails) 2021-07-01 08:36:20 +00:00
ilyaigpetrov
1c479a4e47 Inform FireFox user about WARP proxying (https proxy fails) 2021-06-26 16:51:46 +00:00
ilyaigpetrov
6e24ee0454 Opts page was too narrow, risk and make wider 2021-06-26 16:47:28 +00:00
ilyaigpetrov
e1bdf654f2 Merge branch 'warp-integration' into development 2021-06-26 16:07:01 +00:00
ilyaigpetrov
e73766ae24 Add WARP integration 2021-06-26 16:06:10 +00:00
ilyaigpetrov
5164559fc6 Bump 0.0.1.53 2021-06-25 14:40:53 +00:00
ilyaigpetrov
e344b987c5 Upgrade 'Tested on' versions in the README 2021-05-30 14:57:18 +00:00
ilyaigpetrov
05903e32b3 Merge branch 'fetch-with-retries' into development 2021-05-28 15:28:17 +00:00
ilyaigpetrov
f43eafaf8a Fix retries bug (test4)
Change args scheme in calls of the modified function
2021-05-26 16:53:56 +00:00
ilyaigpetrov
b5154f6453 Add retries (finished, test0) 2021-05-24 17:30:43 +00:00
ilyaigpetrov
699bef6fea Add retries (not tested) 2021-05-22 17:38:32 +00:00
ilyaigpetrov
da7701393e Merge branch 'ffx-layout-fix' into development 2021-05-18 15:45:31 +00:00
ilyaigpetrov
235f6e4b47 Merge branch 'whitelist' into development 2021-05-18 15:45:21 +00:00
ilyaigpetrov
0c5dc8eb26 Fix popup layout widening horizontally. Fix #18 2021-05-18 15:44:05 +00:00
ilyaigpetrov
57a2a8c1ac Add whitelisting for sites to be proxied 2021-05-17 17:12:45 +00:00
ilyaigpetrov
d3caee1483 Start adding whitelist capability 2021-05-15 17:46:14 +00:00
ilyaigpetrov
e4a936c5f1 Fix cases when currentTab.url is falsy (reported for Yandex browser) 2021-03-13 14:37:29 +00:00
ilyaigpetrov
414e2547f3 Upgrade dependencies 2021-02-28 10:56:49 +00:00
ilyaigpetrov
04be2d6164 Bump 0.0.1.52 2021-01-25 10:05:44 +00:00
ilyaigpetrov
e51673f268 Fix migration error from 1.49 2021-01-25 07:20:53 +00:00
ilyaigpetrov
d56a7e7366 Bump 0.0.1.51 2021-01-24 15:21:25 +00:00
ilyaigpetrov
0b13cb1dd0 Fix 2 bugs in exceptions handling 2021-01-18 13:58:30 +00:00
ilyaigpetrov
14f32b4d13 Migrate all exceptions to wildcarded state 2021-01-17 17:02:59 +00:00
ilyaigpetrov
9ef236d604 Hanlde wildcard when assigning a weight to an exception 2021-01-15 17:28:55 +00:00
ilyaigpetrov
7dae51db8c Return to a step back when wildcard is present in the key (not in the value) 2021-01-15 16:59:32 +00:00
ilyaigpetrov
796681ae5a Make proxy's 'No' settable in UI. Refactor 2021-01-14 16:40:04 +00:00
ilyaigpetrov
ccda45a57c Keep objects in mods.in/ex(cluded). Refactor 2021-01-12 17:29:18 +00:00
ilyaigpetrov
e95c186de1 Handle *. in UI for exceptions 2021-01-12 16:00:29 +00:00
ilyaigpetrov
df3ea9e6ad Allow non-wildcard exceptions (no migration or interface yet) 2021-01-12 15:46:32 +00:00
ilyaigpetrov
38e2bb2f3c Refactor one line 2021-01-12 14:18:46 +00:00
ilyaigpetrov
35668f620b Fix broken migration for <=0.0.1.48 2021-01-10 16:43:47 +00:00
ilyaigpetrov
1371dc01cd Merge branch 'production' into development 2020-12-23 14:40:04 +00:00
ilyaigpetrov
95bfd3ae9e Merge branch 'development' into production 2020-12-23 14:37:39 +00:00
ilyaigpetrov
f93e01bb8a Merge firefox-60 to development 2020-12-23 14:36:16 +00:00
ilyaigpetrov
b3997f48ac Bump 0.0.1.50 2020-12-07 17:47:03 +00:00
ilyaigpetrov
1a0c168458 Bump 0.0.1.49 2020-12-07 16:54:51 +00:00
ilyaigpetrov
c566fcecb5 Migrate storage for <=0.0.1.48. Fix ffx bugs 2020-12-07 16:52:09 +00:00
ilyaigpetrov
aa727d9329 Fix chrome.proxy.settings shims for FireFox
Yet it still downloads pac-script twice
2020-12-06 16:43:29 +00:00
ilyaigpetrov
53571f6228 Add chrome.proxy.settings shims for FireFox 2020-12-05 16:28:30 +00:00
ilyaigpetrov
eb996931ae Fix a bug thrown after waking pc up
Handle a case when all pac-script urls fwail
2020-11-09 12:03:45 +00:00
ilyaigpetrov
63f5e6fd08 Bump 0.0.1.48 2020-11-09 07:57:45 +00:00
ilyaigpetrov
fe2e986bfe Turn off TUNN CONN FAILED for chrome. Fix proxy settings setter bug 2020-11-07 15:29:57 +00:00
ilyaigpetrov
da06ea4aac Bump 0.0.47 2020-11-01 12:07:10 +00:00
ilyaigpetrov
e60b8cc96c Truncate long log output to save RAM 2020-11-01 11:07:59 +00:00
ilyaigpetrov
c8e7d7f427 Move promise rejection handler into later promise. Fix #74 2020-11-01 11:01:03 +00:00
ilyaigpetrov
65f712d0a1
Update README.md 2020-10-19 09:37:13 +00:00
ilyaigpetrov
71d1aff6cd
Update README.md 2020-10-19 09:35:53 +00:00
ilyaigpetrov
5287510263 Make ffx blink on TUNNEL CONN FAILED (but popup doesn't show error) 2020-10-18 16:27:57 +00:00
ilyaigpetrov
a12621635b Bump 0.0.1.46 2020-10-18 16:27:25 +00:00
ilyaigpetrov
fb9aa707a6 Add a note for reviewers 2020-10-17 13:44:57 +00:00
ilyaigpetrov
e3c595a447 Don't open new tab if no access to private windows. Rephrase 2020-10-17 13:36:29 +00:00
ilyaigpetrov
73485e8be4 Open howto when extension needs access to private windows 2020-10-17 10:25:16 +00:00
ilyaigpetrov
99a4ff9d24 Don't clear settings that are not set by us 2020-10-16 17:54:20 +00:00
ilyaigpetrov
97ba2697da Clean before the build 2020-10-16 17:19:56 +00:00
ilyaigpetrov
0ffefd7cfc Get rid of obsolete firefox scripts 2020-10-16 17:02:22 +00:00
ilyaigpetrov
747ad70497 Bump 0.0.1.45 2020-10-16 17:01:09 +00:00
ilyaigpetrov
3f0cebebad Bump 0.0.1.44 2020-10-16 17:00:27 +00:00
ilyaigpetrov
4985ef6526 Get rid of obfuscated string constants 2020-10-16 16:01:04 +00:00
ilyaigpetrov
5278c65c90 Use data-url instead of blob. Remove debug logs. Remove ccahiha. 2020-10-16 15:00:09 +00:00
ilyaigpetrov
94aefc8ddc Provide more build/install details for reviewers 2020-10-16 14:13:11 +00:00
ilyaigpetrov
fccc2611b2 Make start command to build for production 2020-10-16 14:07:19 +00:00
ilyaigpetrov
4e870d5b87
Update README.md 2020-10-16 14:06:23 +00:00
ilyaigpetrov
17989f4735 Fix muted errors
New bug spotted: "GETed with success" is logged twice for
proxy.pac.
2020-10-13 16:27:50 +00:00
ilyaigpetrov
7037af70ca Add FireFox 60 support (for testing, part 1)
Some error notifications are broken. Not thoroughly tested.
2020-10-12 17:08:26 +00:00
ilyaigpetrov
8145f5f04a Bump 0.0.1.43 2020-10-12 16:29:21 +00:00
ilyaigpetrov
ea85cf941b Merge branch 'development' into production 2020-10-08 08:20:11 +00:00
ilyaigpetrov
f07f0d1fbb Allow using own proxies only for own sites, see #55 2020-10-03 16:24:14 +00:00
ilyaigpetrov
71fe983cf2 Trim www. on adding an exception, fix #72 2020-10-03 15:54:48 +00:00
ilyaigpetrov
60db8d0752 Bump 0.0.1.42 2020-10-03 15:51:28 +00:00
ilyaigpetrov
21ab71ad44
Update outdated info 2020-09-19 06:20:43 +00:00
ilyaigpetrov
ba19010545 Disable caching 2020-07-23 10:10:22 +00:00
ilyaigpetrov
ed3997272e Bump 0.0.1.41 2020-06-05 15:16:00 +00:00
ilyaigpetrov
84902d8e5a Dirty hack to turn off wrong caching of AntiZapret 2020-06-05 15:15:13 +00:00
ilyaigpetrov
94b4261418 Bump 0.0.1.40 2020-06-01 15:45:23 +00:00
ilyaigpetrov
c2d3e12d63
Update README.md 2020-04-13 16:38:13 +00:00
ilyaigpetrov
0036050e14 Remove non-working OK button for Edge's options page 2020-03-26 16:53:12 +00:00
ilyaigpetrov
288183ddea Indicate last nodejs version tested 2020-03-13 16:24:24 +00:00
ilyaigpetrov
4b27db6285 Make these files unexecutable (chmod -x) 2020-03-13 16:20:13 +00:00
ilyaigpetrov
ad3c390056 Bump 0.0.1.39 2019-10-25 16:20:16 +00:00
ilyaigpetrov
0a0df56dbe Merge branch 'development' into production 2019-10-25 16:19:13 +00:00
ilyaigpetrov
bc2ceed1dc Fix: url may be empty, so check it 2019-10-25 16:09:29 +00:00
ilyaigpetrov
74233d7fa8 Bump 0.0.1.38 2019-09-30 13:24:18 +00:00
ilyaigpetrov
97b6c2cdc3 Merge branch 'development' into production 2019-09-30 12:25:18 +00:00
ilyaigpetrov
b6f95d5829 Fix bug when tooltip is not reachable by mouse 2019-09-30 12:19:51 +00:00
ilyaigpetrov
7069c9a1ff Merge branch 'development' of https://github.com/anticensority/runet-censorship-bypass into development 2019-09-28 14:18:55 +00:00
ilyaigpetrov
bf70de3727 Exclude reserved subnets from replaceDirectWith 2019-09-28 14:18:50 +00:00
ilyaigpetrov
53e64ef61d
Merge pull request #63 from lex111/patch-1
Fix typos
2019-09-25 02:57:48 +00:00
Alexey Pyltsyn
9a7b5407a2
Fix typos 2019-09-25 02:37:44 +03:00
ilyaigpetrov
12db4afe55 Add replaceRedirectWith modifier in own proxies, see #62 2019-09-18 17:12:01 +00:00
ilyaigpetrov
4e736bf403 Merge branch 'development' into production 2019-09-07 16:37:10 +00:00
ilyaigpetrov
a6fd4d44f1 Bump 0.0.1.37 2019-09-07 16:36:51 +00:00
ilyaigpetrov
85edbf75b2 Translate to en more of exceptions editor tab 2019-09-07 16:12:54 +00:00
ilyaigpetrov
55b4ba385a Pac choosing tab is fully translated to en 2019-09-07 15:53:38 +00:00
ilyaigpetrov
426793e700 Translate to en more of PAC choosing tab 2019-09-07 15:28:47 +00:00
ilyaigpetrov
9d5921ae43 Bump 0.0.1.36 2019-08-16 16:35:09 +00:00
ilyaigpetrov
af7a5a24bc Merge branch 'development' into production 2019-08-16 16:34:28 +00:00
ilyaigpetrov
ad8aa3baed Hanlde error when tabId is -1 instead of throwing it 2019-08-16 18:42:40 +05:00
ilyaigpetrov
05d1b6f6be Bump 0.0.1.35 2019-08-12 17:10:18 +05:00
ilyaigpetrov
4704585c1a Merge branch 'development' into production 2019-08-12 17:09:31 +05:00
ilyaigpetrov
faae7c6d4a Protect users from potential error message text injection via url 2019-08-11 21:34:58 +05:00
ilyaigpetrov
2ba422dde7 Fix audit errors for the options page 2019-08-11 21:27:22 +05:00
ilyaigpetrov
7db0946f60 Update gulp and eslint to get rid of some audit errors 2019-08-11 21:20:46 +05:00
ilyaigpetrov
b8d770862e Throw error in strange cases when tabId < 0 2019-08-11 21:15:09 +05:00
ilyaigpetrov
5be69e9c51 Explicitly throw error for bad urls instead of suppressing it 2019-08-11 21:01:09 +05:00
ilyaigpetrov
f87a1c0178
Merge pull request #58 from TemaSM/development
Update URLs in README
2019-06-24 12:53:25 +05:00
Tema Smirnov
a20d36fdb6
Update URLs in README 2019-06-24 10:42:33 +03:00
ilyaigpetrov
b36215f43f
Update FUNDING.yml 2019-06-11 22:27:22 +05:00
ilyaigpetrov
08a3e17642
Create FUNDING.yml 2019-06-11 22:26:00 +05:00
ilyaigpetrov
7256a50804 Bump 0.0.1.34 2019-05-20 01:19:41 -05:00
ilyaigpetrov
e9420a68c9 Merge branch 'development' into production 2019-05-20 01:18:43 -05:00
ilyaigpetrov
7c13d38e4f Make it work for old chrome 58 2019-05-20 01:18:34 -05:00
ilyaigpetrov
1c12ad86c8 Bump 0.0.1.33 2019-05-11 06:22:10 -05:00
ilyaigpetrov
cbd377b33b Merge branch 'development' into production 2019-05-11 06:21:07 -05:00
ilyaigpetrov
719d6eac9c Handle TUNN CONN FAILED, sanitize optioins page url params, fix #50 2019-05-11 06:20:53 -05:00
ilyaigpetrov
1eb005f085
Fix a typo in "Сбросиь" 2019-05-05 11:17:43 -05:00
ilyaigpetrov
b33e038c2e Bump 0.0.1.32 2019-05-04 12:37:12 -05:00
ilyaigpetrov
f37539a19c Merge branch 'development' into production 2019-05-04 12:36:34 -05:00
ilyaigpetrov
60ebdae57f Provide basic English translation, add donate button 2019-05-04 12:20:54 -05:00
ilyaigpetrov
89f394b9a5 Fix options page not showing on Chrome 74 (Chromium 73 works fine) 2019-05-04 12:20:11 -05:00
ilyaigpetrov
4beb6e9fcb Make grep sensitive again 2019-05-04 12:12:51 -05:00
ilyaigpetrov
db4eb6767d Fix tab captions not fitting on options page in the header 2019-05-04 09:55:38 -05:00
ilyaigpetrov
8432bc65de Update babel-related packages, fix license for the options page builder 2019-05-04 09:51:52 -05:00
ilyaigpetrov
186ca1bdb4 Make grep insensetive 2019-05-04 09:35:08 -05:00
Ilya Ig. Petrov
b68151c998 Bump 0.0.1.31 2019-04-15 07:56:39 +00:00
Ilya Ig. Petrov
e6d5be6e56 Merge branch 'development' into production 2019-04-15 07:54:34 +00:00
Ilya Ig. Petrov
d6060e9e9c Update Antizapret proxies for the block informer 2019-04-15 07:16:20 +00:00
Ilya Ig. Petrov
817fa5abe0 Merge branch 'v1.30-refactor' into development 2019-04-04 17:28:59 +00:00
Ilya Ig. Petrov
4965921c06 Comment about having two dates for a pac provider 2019-02-26 15:26:47 +00:00
Ilya Ig. Petrov
26fc0c4de3 Add trailing comma to all the things 2019-02-26 15:09:33 +00:00
Ilya Ig. Petrov
5d64e445fc Declare var near its usage 2019-02-24 17:17:09 +00:00
Ilya Ig. Petrov
8cf2602e61 Change warning message for anticensority pac-script 2019-02-24 17:12:41 +00:00
Ilya Ig. Petrov
927fd7d043 Migrate from gulp 3.x to 4.x dirtily 2019-02-24 16:47:27 +00:00
Ilya Ig. Petrov
2ce48cbd50 Remove unnecessary async, explain *Async in a comment 2019-02-24 16:45:33 +00:00
Ilya Ig. Petrov
68df622d71 Update lockfile for the options page 2019-02-24 16:42:16 +00:00
Ilya Ig. Petrov
a848c159a0 Replace personal email with a team email, update urls 2018-11-14 19:47:34 +05:00
Ilya Ig. Petrov
3159ca910f Update README.md 2018-11-14 17:17:32 +05:00
Ilya Ig. Petrov
9e2f89a235 Update README.md 2018-10-28 20:50:52 +05:00
Ilya Ig. Petrov
9c2b99a738 Bump 0.0.1.30 2018-08-01 17:43:03 +05:00
Ilya Ig. Petrov
66d89a3b97 Merge branch 'development' into production 2018-08-01 17:32:51 +05:00
Ilya Ig. Petrov
2784e8a751 Don't keep ';' inside variables, use it externally 2018-08-01 17:31:05 +05:00
Ilya Ig. Petrov
3f8cd09c0e Don't log large objects (PAC-scripts) 2018-08-01 17:20:52 +05:00
Ilya Ig. Petrov
1a92356e06 Merge pull request #37 from dchusovitin/proxy-priority
Custom (or tor) proxies must have the higher priority
2018-08-01 16:19:06 +05:00
dchusovitin
496073e504 Custom (or tor) proxies must have the higher priority 2018-08-01 01:04:09 +03:00
Ilya Ig. Petrov
1a25e74149 Merge branch 'production' into development
To remove non-merge commits in production that produce no diff.
2018-05-15 22:00:46 +05:00
Ilya Ig. Petrov
6eaec132b3 Bump 0.0.1.29 2018-05-15 21:58:08 +05:00
Ilya Ig. Petrov
2a7a5a12ca Merge branch 'development' into production 2018-05-15 21:56:58 +05:00
Ilya Ig. Petrov
3b03be61c5 No inform for resources from proxy hostname/ip, fixes #32 2018-05-15 21:56:06 +05:00
Ilya Ig. Petrov
77ac9ec63d Merge branch 'development' into production 2018-05-15 20:49:23 +05:00
Ilya Ig. Petrov
1f31f2bce7 Bump 0.0.1.28 2018-05-09 21:30:08 +05:00
Ilya Ig. Petrov
c2985fe072 s/rebrand.ly/git.io for ac-wiki 2018-05-09 21:29:16 +05:00
Ilya Ig. Petrov
859dcc1227 Bump 0.0.1.27 2018-05-09 21:05:47 +05:00
Ilya Ig. Petrov
94cbef746b Flush LastModified during update 2018-05-09 21:04:54 +05:00
Ilya Ig. Petrov
31ca68a918 Bump 0.0.1.26 2018-05-09 20:24:21 +05:00
Ilya Ig. Petrov
6fb1765fcb Never change news link to testing anymore! 2018-05-09 20:23:54 +05:00
Ilya Ig. Petrov
fc3226febd s/rebrand.ly/git.io for a pair of links 2018-05-09 20:04:56 +05:00
Ilya Ig. Petrov
71fcd38349 Bump 0.0.1.25 2018-05-09 19:40:44 +05:00
Ilya Ig. Petrov
03a113119b Merge branch 'development' into production 2018-05-09 19:40:05 +05:00
Ilya Ig. Petrov
13a2708de9 Remove a deprecated url for AC-PAC 2018-05-09 19:23:14 +05:00
Ilya Ig. Petrov
6988d42068 Add localhost to the block-informer 2018-05-09 19:06:20 +05:00
Ilya Ig. Petrov
0d4366712f Swap rebrand.ly/ac-beta-pac for direct urls 2018-05-09 19:05:43 +05:00
Ilya Ig. Petrov
a1ed5db0d1 Fix update bug, more logs, change warning text 2018-05-09 18:05:04 +05:00
Ilya Ig. Petrov
6fe17ced57 Open options page links in bg by default 2018-05-09 16:57:27 +05:00
Ilya Ig. Petrov
4bb8f7d50e Make warning non-fatal 2018-05-09 16:40:58 +05:00
Ilya Ig. Petrov
4f4103405a Fix jerking width of options page on scrolling 2018-05-09 16:26:08 +05:00
Ilya Ig. Petrov
868168b752 Update settings search URL for proxy 2018-05-09 16:03:00 +05:00
Ilya Ig. Petrov
d6d3fb2dc5 Make grep respect ./*.js 2018-05-09 15:56:43 +05:00
Ilya Ig. Petrov
4b5ae6c461 Advise against nodejs 10 2018-05-09 15:53:27 +05:00
Ilya Ig. Petrov
7f7f27a417 npm update 2018-05-09 15:51:18 +05:00
Ilya Ig. Petrov
02ac70b5f6 Fix template escapes and backticks 2018-05-09 15:50:44 +05:00
Ilya Ig. Petrov
ae0fbeaf8a Change error to warning and its text 2018-05-08 21:52:12 +05:00
Ilya Ig. Petrov
72faa8b8a9 Remove AZ heading, add own proxy check on setting Anticensority PAC 2018-05-08 19:47:30 +05:00
Ilya Ig. Petrov
ec6450096f Automatically switch to Antizapret for <=1.23 2018-05-08 18:26:47 +05:00
Ilya Ig. Petrov
0cfbc063f1 Bump 0.0.1.24 2018-05-05 11:20:28 +05:00
Ilya Ig. Petrov
5ed0ced254 Merge branch 'development' into production 2018-05-05 11:18:31 +05:00
Ilya Ig. Petrov
d3b828303c Remove MAC delay for options page 2018-05-03 23:03:00 +05:00
Ilya Ig. Petrov
7b98ed1ce7 Bypass a MAC bug 2018-05-03 22:44:34 +05:00
Ilya Ig. Petrov
e9edd324fc Don't log large objects (PAC-script) 2018-05-03 14:29:23 +05:00
Ilya Ig. Petrov
c9036f038a Fix quotes for grep.sh 2018-05-03 14:21:29 +05:00
Ilya Ig. Petrov
ba43fa9f19 Bump 0.0.1.23 2018-04-18 21:34:40 +05:00
Ilya Ig. Petrov
f9f50a4314 Add a proxy server for ranges 2018-04-18 21:32:50 +05:00
Ilya Ig. Petrov
68d1270c54 Merge branch 'development' of https://github.com/anticensority/runet-censorship-bypass into development 2018-04-18 21:10:33 +05:00
Ilya Ig. Petrov
22deaf6720 Uncomment PAC short url for beta 2018-04-18 20:56:49 +05:00
Ilya Ig. Petrov
f489c05466 Merge branch 'development' into production 2018-04-12 15:55:40 +05:00
Ilya Ig. Petrov
74bd7eb685 Bump 0.0.1.22 2018-04-12 15:33:09 +05:00
Ilya Ig. Petrov
555d2c30bf Hide AZ-heading error (not used yet) 2018-04-12 13:16:34 +05:00
Ilya Ig. Petrov
9ee9954a43 New lock-file for options page 2018-04-12 12:39:21 +05:00
Ilya Ig. Petrov
f9671fb1fe Pass props to super() in PacChooser 2018-04-12 12:37:39 +05:00
Ilya Ig. Petrov
314429cb16 Remove homepage from manifest 2018-04-12 12:36:43 +05:00
Ilya Ig. Petrov
8a243e16be Update README.md 2018-04-12 12:21:24 +05:00
Ilya Ig. Petrov
ea7914e115 Reverse news order (newest top) 2018-04-06 11:29:57 +05:00
Ilya Ig. Petrov
b866245ed0 Change useragent for news on GitHub 2018-04-06 11:23:23 +05:00
Ilya Ig. Petrov
4d22581359 Remove error used for testing 2018-04-06 10:55:26 +05:00
Ilya Ig. Petrov
285c393cd2 Merge branch 'development' into production 2018-04-04 21:45:35 +05:00
Ilya Ig. Petrov
e5c6c281de Edit PAC-scripts description 2018-04-04 21:33:43 +05:00
Ilya Ig. Petrov
4e7bfd7be6 Show AZ heading noncritical error 2018-04-04 21:19:12 +05:00
Ilya Ig. Petrov
eac777406b Bump 0.0.1.21 2018-04-04 20:15:41 +05:00
Ilya Ig. Petrov
c53c38fd4f Make AZ heading noncritical 2018-04-04 20:14:27 +05:00
Ilya Ig. Petrov
1502c4f159 Fix typo 2018-04-04 18:20:55 +05:00
Ilya Ig. Petrov
dd36c63ed7 Replace custom code with symlink-to package 2018-02-23 16:05:56 +05:00
Ilya Ig. Petrov
55c1ccab2a Remove obsolete code in root package.json 2018-02-23 15:54:43 +05:00
Ilya Ig. Petrov
87072aa3c7 Update README.md 2018-02-23 15:40:13 +05:00
Ilya Ig. Petrov
ec5f3b26b7 Update README.md 2018-02-23 15:37:19 +05:00
Ilya Ig. Petrov
cd741414c6 Bump 0.0.1.20 2018-02-23 15:24:47 +05:00
Ilya Ig. Petrov
9596af084e Merge branch 'development' into production 2018-02-23 15:21:44 +05:00
Ilya Ig. Petrov
a78a844d21 Merge pull request #27 from opencollective/opencollective
Open Collective updates
2018-02-23 14:51:14 +05:00
Jess
99e8c105ed Added call to donate after npm install (optional) 2018-02-23 18:33:00 +09:00
Jess
afbe1f4537 Added backers and sponsors on the README 2018-02-23 18:33:00 +09:00
Ilya Ig. Petrov
8d749eb2ae Make HEAD to Antizapret 2018-01-27 17:21:28 +05:00
Ilya Ig. Petrov
c59ffda2e2 Move adding pac kitchen to lower level (during cook) 2018-01-24 19:55:22 +05:00
Ilya Ig. Petrov
a592b4c4ae Bump 0.0.0.19 2018-01-19 15:46:07 +05:00
Ilya Ig. Petrov
59229bc63e Remove unsafe content-security policy used for Firefox 2018-01-19 15:45:50 +05:00
Ilya Ig. Petrov
f40f371dd7 Update README.md 2017-12-21 12:03:20 +05:00
Ilya Ig. Petrov
8bd853fe57 Update README.md 2017-12-19 14:27:35 +05:00
Ilya Ig. Petrov
2576ec99ba Bump 0.0.1.18 2017-12-03 20:07:01 +05:00
Ilya Ig. Petrov
08da89030d Send platform with error info 2017-12-03 19:51:03 +05:00
Ilya Ig. Petrov
49cac9da15 Send useragent with error info 2017-12-03 19:29:27 +05:00
Ilya Ig. Petrov
04a6f7e13a Fove Firefox pac file to its folder 2017-12-03 18:37:40 +05:00
Ilya Ig. Petrov
e7fed46cc9 Remove advert about coworker 2017-12-03 17:40:22 +05:00
Ilya Ig. Petrov
220d368d89 Bump 0.0.1.17 2017-11-29 16:00:24 +05:00
Ilya Ig. Petrov
b45faad6cb Add another type check protection 2017-11-29 15:29:58 +05:00
Ilya Ig. Petrov
4e659dbec9 Resolved conflict 2017-11-29 15:23:26 +05:00
Ilya Ig. Petrov
bc1836b0f8 Merge branch 'development' into production 2017-11-29 15:20:07 +05:00
Ilya Ig. Petrov
b96e12d803 Merge branch 'firefox-port' into development 2017-11-29 14:31:05 +05:00
Ilya Ig. Petrov
c2a3c23e7e Bump 0.0.1.16 2017-11-29 14:27:45 +05:00
Ilya Ig. Petrov
a86b9f6a0e PAC kitchen prettier output 2017-11-29 13:36:02 +05:00
Ilya Ig. Petrov
30875cb9a1 Bump extension version to 0.0.1.15 2017-11-29 13:09:32 +05:00
Ilya Ig. Petrov
a07ecfeaf2 Add more error to ignore list 2017-11-29 13:05:00 +05:00
Ilya Ig. Petrov
498f35df71 Fix bug with no rule returned from PAC 2017-11-28 23:29:12 +05:00
Ilya Ig. Petrov
0b80a6bd18 Release firefox edition separately 2017-11-28 23:23:59 +05:00
Ilya Ig. Petrov
e5b47999b6 Build subpages in beta mode when using start 2017-11-28 17:54:50 +05:00
Ilya Ig. Petrov
73bb56e5e0 Open options page expanded while on addons page 2017-11-25 21:36:42 +05:00
Ilya Ig. Petrov
466fe1451d Rename files, more verbose instructions 2017-11-25 20:30:46 +05:00
Ilya Ig. Petrov
bca0135b77 Add install note 2017-11-25 20:23:43 +05:00
Ilya Ig. Petrov
1191a5e043 Fix bug with undefined cb 2017-11-25 19:32:01 +05:00
Ilya Ig. Petrov
4738bcf9af Persist state between relaunches for Firefox 2017-11-22 16:03:20 +05:00
Ilya Ig. Petrov
a35ab098d4 Bump beta to 0.0.1.14 2017-11-22 15:34:01 +05:00
Ilya Ig. Petrov
aa21b5ad9e Make Firefox load PAC on each start 2017-11-22 15:19:02 +05:00
Ilya Ig. Petrov
609017da1a Bump beta to 0.0.1.13 2017-11-22 15:18:18 +05:00
Ilya Ig. Petrov
8a9eb02d6e Bump beta to 0.0.1.12 2017-11-22 14:33:03 +05:00
Ilya Ig. Petrov
688eef70db Bump beta to 0.0.1.11 2017-11-22 13:13:28 +05:00
Ilya Ig. Petrov
314bf57b94 First working version 2017-11-22 12:13:45 +05:00
Ilya Ig. Petrov
a29cfd3c38 wOMerge branch 'development' into production 2017-11-16 21:06:52 +05:00
Ilya Ig. Petrov
3a79e9738b Bump 0.0.1.11 2017-11-16 21:06:27 +05:00
Ilya Ig. Petrov
b8a03d1329 Bump 0.0.1.11 2017-11-14 13:44:53 +05:00
Ilya Ig. Petrov
8df4e50ebb Fix another bug when details are undefined 2017-11-13 22:53:06 +05:00
Ilya Ig. Petrov
029f80633d Merge branch 'development' into production 2017-11-12 08:31:56 +05:00
Ilya Ig. Petrov
13de0bf079 Bump 0.0.1.10 2017-11-12 08:31:01 +05:00
Ilya Ig. Petrov
46f311678c Wrap update in try/catch, finally force update 2017-11-12 08:30:16 +05:00
Ilya Ig. Petrov
795f21baba Bump 0.0.1.7 2017-11-11 17:18:20 +05:00
Ilya Ig. Petrov
d6037e6810 Merge branch 'development' into production 2017-11-11 12:41:40 +05:00
Ilya Ig. Petrov
676de4c854 Fix link label 2017-11-11 12:37:58 +05:00
Ilya Ig. Petrov
db52a6dbc0 Update lock files (small) 2017-11-11 12:28:31 +05:00
Ilya Ig. Petrov
a1547c1403 Add link to protected proxies docs on UI 2017-11-11 12:27:07 +05:00
Ilya Ig. Petrov
11b2a61ba5 Fix weird bug when are undefined 2017-11-11 12:24:55 +05:00
Ilya Ig. Petrov
88a3810199 Clean from debug msgs 2017-11-01 13:57:09 +05:00
Ilya Ig. Petrov
ec692851d4 s/cb/await 2017-11-01 13:47:29 +05:00
Ilya Ig. Petrov
558d67204b Fix migration bug 2017-11-01 00:19:45 +05:00
Ilya Ig. Petrov
9b35c413cc Handle empty username case 2017-11-01 00:19:10 +05:00
Ilya Ig. Petrov
8f1ce3b6ea Auth seems to work, not tested 2017-10-31 23:30:42 +05:00
Ilya Ig. Petrov
e4bf2292b4 Fix sanitizing logic to use new utils parser 2017-10-31 21:20:56 +05:00
Ilya Ig. Petrov
9495910261 Move proxy scheme parsing to utils 2017-10-31 21:08:12 +05:00
Ilya Ig. Petrov
bc439c22f7 Allow following spaces in name and password 2017-10-31 19:57:13 +05:00
Ilya Ig. Petrov
b0f9cd2694 Take creds, don't repsect old ; with no \n 2017-10-31 19:20:16 +05:00
Ilya Ig. Petrov
18d3dda63e Produce ;\n, but still take in old format 2017-10-31 18:43:30 +05:00
Ilya Ig. Petrov
41913e7dad Fix bug with tmlp format, do raw migrate 2017-10-31 18:42:20 +05:00
Ilya Ig. Petrov
c9c7b15d9b Define migration replacement 2017-10-31 17:51:15 +05:00
Ilya Ig. Petrov
15e95d6e07 Ready for migration of custom proxies format 2017-10-31 17:47:01 +05:00
Ilya Ig. Petrov
b0f826dab6 Add api to compare versions 2017-10-31 17:25:56 +05:00
Ilya Ig. Petrov
56a0daf635 Restyle, fix old update bug 2017-10-31 17:18:53 +05:00
Ilya Ig. Petrov
98cbd5fd02 Start adding auth support 2017-10-18 20:04:42 +05:00
Ilya Ig. Petrov
5f3da48cc9 More comments and restyle 2017-10-17 22:31:55 +05:00
Ilya Ig. Petrov
7ac474a5e7 Parse credentialized (creded) proxies 2017-10-17 21:35:01 +05:00
Ilya Ig. Petrov
e37a376c53 Restyle 2017-10-17 21:34:03 +05:00
Ilya Ig. Petrov
8ef11c4324 Update generator url 2017-10-07 18:52:03 +05:00
Ilya Ig. Petrov
5c9bfb455d More verbose comment 2017-10-05 22:33:48 +05:00
Ilya Ig. Petrov
7fd0d77a95 Exclude 'dist' from grep 2017-10-05 22:28:33 +05:00
Ilya Ig. Petrov
1d4c74b2b4 Update urls of ac PAC-script 2017-09-17 22:57:00 +05:00
Ilya Ig. Petrov
26d9199ee0 Mend build scripts 2017-09-17 22:33:03 +05:00
Ilya Ig. Petrov
031e60c72f Bump 0.0.1.6 2017-09-17 22:32:22 +05:00
58 changed files with 25135 additions and 7915 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # ilyaigpetrov
patreon: # Replace with a single Patreon username
open_collective:
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://github.com/anticensority/runet-censorship-bypass/wiki/Поддержать

0
.gitignore vendored Executable file → Normal file
View File

78
README.md Executable file → Normal file
View File

@ -1,35 +1,71 @@
# [Maintainer Needed! Нужен разработчик!](https://github.com/anticensorship-russia/chromium-extension/issues/2)
If you __unstar__, please, [leave us a note](https://github.com/anticensority/runet-censorship-bypass/issues) why you do so.
Also, if you __unstar__, please, [leave us a note](https://github.com/anticensorship-russia/chromium-extension/issues) why you do so.
[d1]: https://img.shields.io/badge/Поддержать-❤-green.svg
[d2]: https://github.com/anticensority/runet-censorship-bypass/wiki/Поддержать
# Russian Anti-Censorship on PAC-Scripts
[![Поддержать][d1]][d2]
[![Backers on Open Collective](https://opencollective.com/anticensority/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/anticensority/sponsors/badge.svg)](#sponsors)
This repo contains:
# Russian Anticensorship on PAC-Scripts
1. Chrome Extension to bypass censorship in Russia:
[WebStore](https://chrome.google.com/webstore/detail/npgcnondjocldhldegnakemclmfkngch)
| [Sources](https://github.com/ilyaigpetrov/anti-censorship-russia/tree/master/extensions/chromium/minimalistic-pac-setter)
2. Proof of concept PAC-script generator based on https://github.com/zapret-info/z-i
3. ~~PAC-scripts performance analyses of scripts generated~~ (doesn't take parse time into account)
4. Based on the research of step 3 [the final PAC-generator][pac-generator] was written as a Google App Script in JavaScript which is triggered every two hours to generate and publish PAC-script on Google Drive (don't use direct URL without extension, please, URL will be periodically changed to counter abuse).
This repo contains an extension for Chromium and FireFox that helps to bypass censorship in Russia: [WebStore](https://chrome.google.com/webstore/detail/npgcnondjocldhldegnakemclmfkngch)
| [Sources](./extensions/chromium/runet-censorship-bypass).
This extension uses pac scripts, one of which (anticensority) is generated by this [pac-generator].
[pac-generator]: https://script.google.com/d/1RlqqfUmYNpEhekySfOqdzJ8L4eV1GsHYDjPD1DexxEW0RcGvuCSQlWa0/edit?usp=sharing
[pac-generator]: https://github.com/anticensority/pac-script-generator
## Install / Установка
1. [Chrome Web Store](https://chrome.google.com/webstore/detail/обход-блокировок-рунета/npgcnondjocldhldegnakemclmfkngch)
2. [Chrome Web Store (MINI)](https://chrome.google.com/webstore/detail/обход-блокировок-рунета-м/gnknjnebjldmkpmlhjipalimhjofpgho)
3. [Microsoft Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/обход-блокировок-рунета/ajgpnodjpffiagcfmifildjpoaeiobfh)
4. [Microsoft Edge Add-ons (MINI)](https://microsoftedge.microsoft.com/addons/detail/обход-блокировок-рунета-м/cjppllmpmkpjfchbaoebeneghcbmlibj)
5. [FireFox Add-ons](https://addons.mozilla.org/ru/firefox/addon/обход-блокировок-рунета/).
6. Opera: сначала [установщик расширений из WebStore](https://addons.opera.com/ru/extensions/details/install-chrome-extensions/) (от команды Opera), затем см. пункты 1 и 2 выше.
7. Пакеты для автономной (offline) установки / Packages for offline installation: https://github.com/anticensority/runet-censorship-bypass/releases.
Из-за блокировок адресов Google расширение может не устанавливаться из WebStore. Подробности и способы установки см. https://github.com/anticensority/runet-censorship-bypass/wiki/Автономная-установка-расширения.
## Why I do This
I believe __information mustn't be blocked based on political or other subjective views__.
See [my arguments against censorship (ru)](https://github.com/anticensority/runet-censorship-bypass/wiki/Почему-мы-это-делаем%3F-Аргументы-против-цензуры).
My maxim is _"Your freedom ends when it starts to confine the freedom of others"_.
See [my other arguments against censorship (ru)](https://gist.github.com/ilyaigpetrov/9452b93ef3d7dd3d8cc2)
Looking at how Russian government [distorts TV](https://therussianreader.wordpress.com/2015/11/22/russian-truckers-strike-dagestan/) and blocks [critics of Putin](http://www.reuters.com/article/2014/03/13/us-russia-internet-idUSBREA2C21L20140313),
Looking at how Russian government [distorts TV](https://therussianreader.wordpress.com/2015/11/22/russian-truckers-strike-dagestan/) and blocks [critics of Putin](https://www.reuters.com/article/us-russia-internet-idUSBREA2C21L20140313),
I decided to write an anti-censorship extension for Chromium before they strike me first.
## How it Works
0. PAC script is a JavaScript file, triggered on every URL request, which says browser which proxy to use if any for this particular URL.
1. The Chrome Extension sets PAC script in browser settings and keeps it synced with PAC script on the server (offering Antizapret (hosted on a dedicated server) or Anticensority (hosted on GitHub + CloudFlare)).
2. On every request PAC script checks if host is blocked or if its IP is blocked.
3. If address is blocked PAC script returns proxy server to the browser, both Antizapret and Anticensority use Antizapret proxy servers.
0. PAC script is a JavaScript file, triggered on every URL request, which tells the browser which proxy to use if any for this particular URL.
1. The Chrome Extension sets the PAC-script in browser settings and keeps it synced with the PAC script on the server. It offers Antizapret (hosted on a dedicated server) or Anticensority (hosted on GitHub) built-in PAC scripts for the user choice.
2. On every request the PAC script checks if the host is blocked or if its IP is blocked.
3. If an address is blocked, the PAC script returns the proxy server to the browser. The Antizapret PAC script uses its own proxy servers and the Anticensority PAC-script uses local Tor.
4. PAC scripts on servers are updated periodically from https://github.com/zapret-info/z-i.
## Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/anticensority/runet-censorship-bypass/graphs/contributors"><img src="https://opencollective.com/anticensority/contributors.svg?width=890&button=false?force" /></a>
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/anticensority#backer)]
<a href="https://opencollective.com/anticensority#backers" target="_blank"><img src="https://opencollective.com/anticensority/backers.svg?width=890"></a>
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/anticensority#sponsor)]
<a href="https://opencollective.com/anticensority/sponsor/0/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/1/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/2/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/3/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/4/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/5/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/6/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/7/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/8/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/anticensority/sponsor/9/website" target="_blank"><img src="https://opencollective.com/anticensority/sponsor/9/avatar.svg"></a>

View File

@ -1,30 +1,33 @@
# Dev
# Install
Linting JS: `npm run lint`
Tested on:
# О расширении
NodeJS: v16.1.0.
NPM: 7.11.2.
OS: Linux Mint 20 Xfce Edition.
Обход интернет-цензуры в России пока что не является преступлением.
```
npm install
cd src/extension-common/pages/options/
npm install
cd -
Расширение позволяет обходить блокировки РосКомНадзора, давая вам доступ
к библиотекам, энциклопедиям, сайтам оппозиционеров, а также к неповинным
сайтам, случайно заблокированным в силу разных причин.
# For debugging:
npm start
# Use your build/extension-beta
Проксирует только заблокированные сайты, оставляя нетронутыми все остальные.
# For production:
npm start
# Use your build/extension-full or build/extension-mini
```
Устанавливает PAC-скрипт, работающий через сервера anticenz.org и antizapret.prostovpn.org.
# For Reviewers
Обновляет PAC-скрипт каждые 4 часа, что составляет примерно 7MB трафика в сутки.
Также расширение постоянно потребляет ~15MB памяти для информирования о блокировках через иконку.
See ./src/extension-common/FOR_REVIEWERS.md.
Синяя лента кампания фонда EFF в защиту свобод слова, прессы и союзов.
# Release Instructions
Если расширение не работает: https://git.io/vgDDj
Антицензура на Реддите: https://www.reddit.com/r/anticensorship_russia
Группа в G+: https://goo.gl/Lh0Cjh
История изменений: https://github.com/ilyaigpetrov/anti-censorship-russia/releases
# Дополнительно
Иконка синей ленты: http://www.iconsdb.com/icon-sets/cardboard-blue-icons/ribbon-12-icon.html
1. `npm run release`
2. `vim src/templates-data.js` and bump version.
3. Commit bumped version.
4. Merge development to production (usually after deployment and testing and many patches).

View File

@ -0,0 +1,25 @@
# О расширении
Обход интернет-цензуры в России пока что не является преступлением.
Расширение позволяет обходить блокировки РосКомНадзора, давая вам доступ
к библиотекам, энциклопедиям, сайтам оппозиционеров, а также к неповинным
сайтам, случайно заблокированным в силу разных причин.
Проксирует только заблокированные сайты, оставляя нетронутыми все остальные.
Устанавливает PAC-скрипт, работающий через сервера anticenz.org и antizapret.prostovpn.org.
Обновляет PAC-скрипт каждые 4 часа, что составляет примерно 7MB трафика в сутки.
Также расширение постоянно потребляет ~15MB памяти для информирования о блокировках через иконку.
Синяя лента кампания фонда EFF в защиту свобод слова, прессы и союзов.
Если расширение не работает: https://git.io/vgDDj
Антицензура на Реддите: https://www.reddit.com/r/anticensorship_russia
История изменений: https://github.com/anticensority/runet-censorship-bypass/releases
# Дополнительно
Иконка синей ленты: http://www.iconsdb.com/icon-sets/cardboard-blue-icons/ribbon-12-icon.html

View File

@ -1 +1 @@
grep -r $@ ./src --exclude-dir=vendor --exclude-dir=node_modules
grep -r "$@" ./*.js ./src --exclude-dir=vendor --exclude-dir=node_modules --exclude-dir=dist

View File

@ -3,7 +3,7 @@
const gulp = require('gulp');
const del = require('del');
const through = require('through2');
const PluginError = require('gulp-util').PluginError;
const PluginError = require('plugin-error');
const changed = require('gulp-changed');
const PluginName = 'Template literals';
@ -29,7 +29,7 @@ const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
}, { keys: [], values: [] });
try {
file.contents = new Buffer(
file.contents = Buffer.from(
(new Function(...keys, 'return `' + String(file.contents) + '`;'))(...values)
);
} catch(e) {
@ -43,81 +43,65 @@ const templatePlugin = (context) => through.obj(function(file, encoding, cb) {
});
gulp.task('default', ['build']);
gulp.task('clean', function(cb) {
const clean = function(cb) {
//return del.sync('./build');
del.sync('./build');
return cb();
});
};
const contexts = require('./src/templates-data').contexts;
const excFolder = (name) => [`!./src/**/${name}`, `!./src/**/${name}/**/*`];
const excluded = [ ...excFolder('test') , ...excFolder('node_modules'), ...excFolder('src') ];
const commonWoTests = ['./src/extension-common/**/*', ...excluded];
const miniDst = './build/extension-mini';
const fullDst = './build/extension-full';
const betaDst = './build/extension-beta';
const firefoxDst = './build/extension-firefox';
gulp.task('_cp-common', ['clean'], function(cb) {
const commonSrc = './src/extension-common/**/*';;
const miniSrc = './src/extension-mini/**/*';
const fullSrc = './src/extension-full/**/*';
const firefoxSrc = './src/extension-firefox/**/*';
let fins = 0;
const intheend = () => {
if (++fins === 2) {
cb();
}
};
const joinSrc = (...args) => [...args, ...excluded];
gulp.src(commonWoTests)
//.pipe(changed(miniDst))
.pipe(templatePlugin(contexts.mini))
.pipe(gulp.dest(miniDst))
.on('end', intheend);
const copyMini = function(cb) {
gulp.src(commonWoTests)
//.pipe(changed(fullDst))
.pipe(templatePlugin(contexts.full))
.pipe(gulp.dest(fullDst))
.on('end', intheend);
gulp.src(commonWoTests)
//.pipe(changed(fullDst))
.pipe(templatePlugin(contexts.beta))
.pipe(gulp.dest(betaDst))
.on('end', intheend);
});
gulp.task('_cp-mini', ['_cp-common'], function(cb) {
gulp.src(['./src/extension-mini/**/*', ...excluded])
gulp.src(joinSrc(commonSrc, miniSrc))
//.pipe(changed(miniDst))
.pipe(templatePlugin(contexts.mini))
.pipe(gulp.dest(miniDst))
.on('end', cb);
});
};
gulp.task('_cp-full', ['_cp-common'], function(cb) {
const copyFull = function(cb) {
gulp.src(['./src/extension-full/**/*', ...excluded])
gulp.src(joinSrc(commonSrc, fullSrc))
//.pipe(changed(fullDst))
.pipe(templatePlugin(contexts.full))
.pipe(gulp.dest(fullDst))
.on('end', cb);
});
};
gulp.task('_cp-beta', ['_cp-common'], function(cb) {
const copyBeta = function(cb) {
gulp.src(['./src/extension-full/**/*', ...excluded])
gulp.src(joinSrc(commonSrc, fullSrc))
//.pipe(changed(fullDst))
.pipe(templatePlugin(contexts.beta))
.pipe(gulp.dest(betaDst))
.on('end', cb);
});
};
gulp.task('build:all', ['_cp-mini', '_cp-full', '_cp-beta']);
gulp.task('build', ['_cp-full']);
const buildAll = gulp.series(clean, gulp.parallel(copyMini, copyFull, copyBeta));
const buildBeta = copyBeta;
module.exports = {
default: buildAll,
buildAll,
buildBeta,
};

File diff suppressed because it is too large Load Diff

View File

@ -3,27 +3,29 @@
"version": "0.0.19",
"description": "Development tools for chromium extension",
"scripts": {
"postinstall": "node --use_strict -e \"const fs = require('fs'), path = 'node_modules/_project-root'; fs.unlink(path, ()=> fs.symlinkSync('..', path, 'dir'));\"",
"lint": "eslint ./src/**/*.js --ignore-pattern vendor",
"gulp": "gulp",
"test": "mocha --recursive ./src/**/test/*",
"subpages": "cd ./src/extension-common/pages/options/ && npm run build && cd -",
"start": "npm run subpages && npm run gulp",
"beta": "npm run subpages && npm run gulp build:all"
"subpages:dev": "cd ./src/extension-common/pages/options/ && npm run build:dev:nocomp && cd -",
"start": "npm run release",
"release": "npm run subpages && npx gulp -- buildAll"
},
"author": "Ilya Ig. Petrov",
"license": "GPLv3",
"devDependencies": {
"chai": "^3.5.0",
"eslint": "^3.15.0",
"eslint-config-google": "^0.7.1",
"gulp-changed": "^3.1.0",
"mocha": "^3.3.0",
"sinon-chrome": "^2.2.1"
"chai": "^4.3.0",
"eslint": "^7.19.0",
"eslint-config-google": "^0.14.0",
"gulp-changed": "^4.0.2",
"mocha": "^8.2.1",
"sinon-chrome": "^3.0.1",
"symlink-to": "^0.0.4"
},
"dependencies": {
"del": "^2.2.2",
"gulp": "^3.9.1",
"through2": "^2.0.3"
"del": "^6.0.0",
"gulp": "^4.0.2",
"plugin-error": "^1.0.1",
"through2": "^4.0.2"
}
}

View File

@ -1,5 +1,7 @@
'use strict';
console.log('Extension started.');
{
const IF_DEBUG = true;
@ -39,15 +41,18 @@
},
lastError: undefined,
checkChromeError() {
// Chrome API calls your cb in a context different from the point of API
// method invokation.
const err = chrome.runtime.lastError || chrome.extension.lastError;
const err = chrome.runtime.lastError || chrome.extension.lastError || self.lastError;
if (!err) {
return;
}
console.warn('API returned error:', err);
delete self.lastError;
return new Error(err.message); // Add stack.
},
@ -71,6 +76,19 @@
},
getOrDie(cb = self.mandatory()) {
return self.chromified((err, ...args) => {
if (err) {
throw err;
}
cb(...args);
});
},
getProp(obj, path = self.mandatory()) {
const props = path.split('.');
@ -140,6 +158,32 @@
},
promisedLocalStorage: {
get(key) {
return new Promise((resolve) => (
chrome.storage.local.get(
key,
window.utils.getOrDie((storage) => resolve(key ? storage[key] : storage)),
)
));
},
set(items) {
return new Promise((resolve) => (
chrome.storage.local.set(items, resolve)
));
},
remove(keys) {
return new Promise((resolve) => (
chrome.storage.local.remove(keys, resolve)
));
},
clear() {
return new Promise((resolve) => (
chrome.storage.local.clear(resolve)
));
},
},
/*
* Possible values for levelOfControl:
*
@ -168,7 +212,7 @@
searchSettingsForUrl(niddle) {
return 'chrome://settings/search#' + (chrome.i18n.getMessage(niddle) || niddle);
return 'chrome://settings/?search=' + (chrome.i18n.getMessage(niddle) || niddle);
},
@ -176,19 +220,86 @@
return chrome.i18n.getMessage('noControl') +
` <a href="${ this.searchSettingsForUrl('proxy') }">
${ chrome.i18n.getMessage('which') }
${ chrome.i18n.getMessage('WhichQ') }
</a>`;
},
},
parseProxyScheme(proxyAsStringRaw) {
const proxyAsString = proxyAsStringRaw.trim();
const [type] = proxyAsString.split(/\s+/);
/*
if (!/^[a-zA-Z0-9]+$/.test(type)) {
throw new Error(`${type} is not a proxy type!`);
}
JS has no code blocks in RE, seems safe to omit this check.
*/
const typeRe = new RegExp(`^${type}\\s+`, 'g');
const crededAddr = proxyAsString.replace(typeRe, '');
let parts;
parts = crededAddr.split('@');
let [creds, addr] = [parts.slice(0, -1).join('@'), parts[parts.length - 1]];
const [hostname, port] = addr.split(':');
parts = creds.split(':')
const username = parts[0];
const password = parts.slice(1).join(':');
return {
type,
username,
password,
hostname,
port,
creds,
}
},
openAndFocus(url) {
chrome.tabs.create(
{url: url},
(tab) => chrome.windows.update(tab.windowId, {focused: true})
);
},
};
const max = 2**16;
const versionToArray = (v) => [ ...v.split('.'), 0, 0, 0].slice(0,4);
const versionToInt = (v) => versionToArray(v)
.reverse()
.reduce((acc, vv, i) => acc + parseInt(vv)*(max**i), 0);
const compareVersions = (a, b) => versionToInt(a) - versionToInt(b);
const ifFirefox = navigator.userAgent.toLowerCase().includes('firefox');
let give;
const promise = !ifFirefox ? Promise.resolve() : new Promise((resolve) => {
give = resolve;
});
window.apis = {
consent: {
promise,
give,
},
platform: {
ifFirefox,
},
version: {
ifMini: false,
build: chrome.runtime.getManifest().version.replace(/\d+\.\d+\./g, ''),
isLeq: (a, b) => compareVersions(a, b) <= 0,
},
};

View File

@ -8,6 +8,9 @@
const errorJsonReplacer = function errorJsonReplacer(key, value) {
// fooWindow.ErrorEvent !== barWindow.ErrorEvent
if (value === window) {
return; // STUPID, because other window object may be passed.
}
if (!( value && value.constructor
&& ['Error', 'Event'].some(
(suff) => value.constructor.name.endsWith(suff)
@ -50,15 +53,6 @@
};
const openAndFocus = function openAndFocus(url) {
chrome.tabs.create(
{url: url},
(tab) => chrome.windows.update(tab.windowId, {focused: true})
);
};
const ifPrefix = 'if-on-';
const extName = chrome.runtime.getManifest().name;
const extVersion = window.apis.version.build;
@ -72,10 +66,12 @@
const errors = err ? {[type]: err} : this.idToError;
const json = JSON.stringify(errors, errorJsonReplacer, 0);
openAndFocus(
'http://rebrand.ly/ac-error/?json=' + encodeURIComponent(json) +
window.utils.openAndFocus(
'https://anticensority.github.io/error/?json=' + encodeURIComponent(json) +
(type ? '&type=' + encodeURIComponent(type) : '') +
'&version=' + chrome.runtime.getManifest().version
'&version=' + chrome.runtime.getManifest().version +
'&useragent=' + encodeURIComponent(navigator.userAgent) +
'&platform=' + encodeURIComponent(navigator.platform),
);
},
@ -114,20 +110,22 @@
isControllable(details) {
this.ifControllable = window.utils.areSettingsControllableFor(details);
if (details) {
this.ifControllable = window.utils.areSettingsControllableFor(details);
if (this.ifControllable) {
this.ifControlled = window.utils.areSettingsControlledFor(details);
} else {
this.ifControlled = false;
}
if (this.ifControllable) {
this.ifControlled = window.utils.areSettingsControlledFor(details);
} else {
this.ifControlled = false;
}
if (this.ifControlled) {
chrome.browserAction.setIcon( {path: './icons/default-128.png'} );
} else {
chrome.browserAction.setIcon({
path: './icons/default-grayscale-128.png',
});
if (this.ifControlled) {
chrome.browserAction.setIcon( {path: './icons/default-128.png'} );
} else {
chrome.browserAction.setIcon({
path: './icons/default-grayscale-128.png',
});
}
}
return this.ifControllable;
@ -136,7 +134,9 @@
isControlled(details) {
this.isControllable(details);
if (details) {
this.isControllable(details);
}
return this.ifControlled;
},
@ -148,7 +148,9 @@
timeouted(
(details) => {
this.isControllable(details);
if (details) {
this.isControllable(details);
}
cb();
}
@ -175,16 +177,15 @@
const message = errOrMessage.message || errOrMessage.toString();
chrome.notifications.create(
id,
{
Object.assign({
title: title,
message: message,
contextMessage: context,
requireInteraction: ifSticky,
type: 'basic',
iconUrl: './icons/' + icon,
appIconMaskUrl: './icons/default-mask-128.png',
isClickable: true,
}
}, window.apis.platform.ifFirefox ? {} : { requireInteraction: ifSticky }),
);
},
@ -232,7 +233,7 @@
chrome.notifications.clear(notId);
if(notId === 'no-control') {
return openAndFocus(
return window.utils.openAndFocus(
window.utils.messages.searchSettingsForUrl('proxy')
);
}
@ -242,7 +243,7 @@
handlers.installListenersOn(window, 'BG');
chrome.proxy.onProxyError.addListener( timeouted( (details) => {
(chrome.proxy.onProxyError || chrome.proxy.onError).addListener( timeouted( (details) => {
if (!handlers.ifControlled) {
return;
@ -253,7 +254,11 @@
error: "net::ERR_PAC_SCRIPT_FAILED",
fatal: false,
*/
const ifConFail = details.error === 'net::ERR_PROXY_CONNECTION_FAILED';
const ifConFail = [
'net::ERR_TUNNEL_CONNECTION_FAILED',
'net::ERR_PROXY_CONNECTION_FAILED',
].includes(details.error);
if (ifConFail) {
// Happens if you return neither prixies nor "DIRECT".
// Ignore it.
@ -262,7 +267,7 @@
console.warn('PAC ERROR', details);
// TOOD: add "view pac script at this line" button.
handlers.mayNotify('pac-error', 'Ошибка PAC!',
details.error + '\n' + details.details,
(details.error || details.message /* Firefox */) + '\n' + details.details,
{icon: 'pac-error-128.png'}
);
@ -270,14 +275,14 @@
chrome.proxy.settings.onChange.addListener( timeouted( (details) => {
console.log('Proxy settings changed.', details);
console.log('Proxy settings changed:', details.levelOfControl);
const noCon = 'no-control';
const ifWasControllable = handlers.ifControllable;
if ( !handlers.isControllable(details) && ifWasControllable ) {
handlers.mayNotify(
noCon,
chrome.i18n.getMessage('noControl'),
chrome.i18n.getMessage('which'),
chrome.i18n.getMessage('WhichQ'),
{icon: 'no-control-128.png', ifSticky: false}
);
} else {

View File

@ -69,7 +69,7 @@
);
}
console.log('GETed with success:', url, Date.now() - start);
console.log('GETed with success:', url.substr(0, 100), Date.now() - start);
textCb();
},
@ -78,6 +78,31 @@
},
head(url, cb = mandatory()) {
const start = Date.now();
fetch(url, {cache: 'no-store', method: 'HEAD'}).then(
(res) => {
const status = res.status;
if ( !( status >= 200 && status < 300 || status === 304 ) ) {
return cb(
errorsLib.clarify(
res,
'Получен ответ с неудачным HTTP-кодом ' + status + '.'
)
);
}
console.log('HEADed with success:', url, Date.now() - start);
cb();
},
errorsLib.clarifyThen(checkCon, cb)
);
},
};
}

View File

@ -0,0 +1,64 @@
'use strict';
if (window.apis.platform.ifFirefox) {
const prefix = 'firefox-only';
const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
chrome.proxy.settings.set = function(details, cb) {
const pac = window.utils.getProp(details, 'value.pacScript') || {};
if (!(pac && pac.data)) {
return originalSet(details, cb);
}
const blob = new Blob([pac.data], { type : 'application/x-ns-proxy-autoconfig' });
const blobUrl = URL.createObjectURL(blob);
originalSet({
value: {
proxyType: 'autoConfig',
autoConfigUrl: blobUrl,
},
}, window.utils.chromified( async (err) => {
if (err) {
window.utils.lastError = err;
cb();
return;
}
await window.utils.promisedLocalStorage.set({ [`${prefix}-pac-data`]: pac.data });
cb();
}));
};
const originalGet = chrome.proxy.settings.get.bind( chrome.proxy.settings );
chrome.proxy.settings.get = function(details, cb) {
originalGet(details, window.utils.chromified(async (err, originalDetails) => {
if (err) {
window.utils.lastError = err;
cb(originalDetails);
return;
}
let pacData = await window.utils.promisedLocalStorage.get(`${prefix}-pac-data`);
if (!pacData || !Object.keys(pacData).length) {
cb(originalDetails);
return;
}
cb(Object.assign(
originalDetails,
{
value: {
mode: 'pac_script',
pacScript: {
data: pacData,
},
},
}
));
}));
};
const originalClear = chrome.proxy.settings.clear.bind( chrome.proxy.settings );
chrome.proxy.settings.clear = async function(details, cb) {
await window.utils.promisedLocalStorage.remove(`${prefix}-pac-data`);
originalClear(details, cb);
};
}

View File

@ -12,6 +12,57 @@
const ifIncontinence = 'if-incontinence';
const modsKey = 'mods';
let proxyHostToCredsList = {};
const ifAuthSupported = chrome.webRequest && chrome.webRequest.onAuthRequired && !window.apis.version.ifMini;
if (ifAuthSupported) {
const requestIdToTries = {};
chrome.webRequest.onAuthRequired.addListener(
(details) => {
if (!details.isProxy) {
return {};
}
const proxyHost = `${details.challenger.host}:${details.challenger.port}`;
const credsList = proxyHostToCredsList[proxyHost];
if (!credsList) {
return {}; // No creds found for this proxy.
}
const requestId = details.requestId;
const tries = requestIdToTries[requestId] || 0;
if (tries > credsList.length) {
return {}; // All creds for this proxy were tried already.
}
requestIdToTries[requestId] = tries + 1;
return {
authCredentials: credsList[tries],
};
},
{urls: ['<all_urls>']},
['blocking'],
);
const forgetRequestId = (details) => {
delete requestIdToTries[details.requestId];
};
chrome.webRequest.onCompleted.addListener(
forgetRequestId,
{urls: ['<all_urls>']},
);
chrome.webRequest.onErrorOccurred.addListener(
forgetRequestId,
{urls: ['<all_urls>']},
);
}
const getDefaultConfigs = () => ({// Configs user may mutate them and we don't care!
ifProxyHttpsUrlsOnly: {
@ -28,7 +79,7 @@
},
ifProhibitDns: {
dflt: false,
label: 'запретить опредление по IP/DNS',
label: 'запретить определение по IP/DNS',
desc: 'Пытается запретить скрипту использовать DNS, без которого определение блокировки по IP работать не будет (т.е. будет разблокироваться меньше сайтов). Используйте, чтобы получить прирост в производительности или если вам кажется, что мы проксируем слишком много сайтов. Запрет действует только для скрипта, браузер и др.программы продолжат использование DNS.',
order: 2,
},
@ -50,12 +101,19 @@
dflt: false,
category: 'ownProxies',
label: 'использовать СВОЙ локальный Tor',
desc: 'Установите <a href="https://rebrand.ly/ac-tor">Tor</a> на свой компьютер и используйте его как прокси-сервер. <a href="https://rebrand.ly/ac-tor">ВАЖНО</a>',
desc: 'Установите <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Расширение-и-TOR">Tor</a> на свой компьютер и используйте его как прокси-сервер. <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Расширение-и-TOR#важно">ВАЖНО</a>.',
order: 5,
},
ifUseLocalWarp: {
dflt: false,
category: 'ownProxies',
label: 'использовать WARP как прокси',
desc: 'Использовать СВОЙ локальный CloudFlare WARP (<a href="https://one.one.one.one">https://one.one.one.one</a>) в качестве прокси.',
order: 5.5,
},
exceptions: {
category: 'exceptions',
dflt: null,
category: 'exceptions',
},
ifMindExceptions: {
dflt: true,
@ -64,13 +122,31 @@
desc: 'Учитывать сайты, добавленные вручную. Только для своих прокси-серверов! Без своих прокси работать не будет.',
order: 6,
},
whitelist: {
dflt: [],
category: 'exceptions',
},
ifMindWhitelist: {
dflt: false,
category: 'exceptions',
label: 'Ограничиться только <a href="../exceptions/index.html">белым списком</a>',
desc: 'Разрешить расширению работать только с адресами из белого списка.',
order: 6.5,
},
customProxyStringRaw: {
dflt: '',
category: 'ownProxies',
label: 'использовать СВОИ прокси',
url: 'https://rebrand.ly/ac-own-proxy',
url: 'https://github.com/anticensority/runet-censorship-bypass/wiki/Свои-прокси-в-расширении',
order: 7,
},
ifUseOwnProxiesOnlyForOwnSites: {
dflt: false,
category: 'ownProxies',
label: 'СВОИ прокси только для СВОИХ сайтов',
desc: 'Не использовать СВОИ прокси для всех сайтов из PAC-скрипта, а только для добавленных вручную исключений.',
order: 7.5,
},
ifProxyMoreDomains: {
ifDisabled: true,
dflt: false,
@ -79,6 +155,14 @@
desc: 'Проксировать особые домены. Необходима поддержка со стороны СВОИХ прокси.',
order: 8,
},
replaceDirectWith: {
ifDisabled: true,
dflt: false,
category: 'ownProxies',
label: 'подменять DIRECT на',
desc: 'Использовать в PAC-скрипте указанную строку для запросов напрямую (вместо директивы DIRECT). Данная строка не проверяется на требования к шифрованию связи до прокси! Строка должна соответствовать формату возвращаемого значения PAC-скрипта, который подобен <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Свои-прокси-в-расширении#формат">формату своих прокси</a>.',
order: 9,
},
});
@ -91,16 +175,15 @@
return acc;
}, {});
};
const getCurrentConfigs = function getCurrentConfigs() {
const getCurrentConfigs = function getCurrentConfigs(ifRaw = false) {
const oldMods = kitchenState(modsKey);
/*if (oldMods) {
if (ifRaw) {
// No migration!
return oldMods;
}*/
}
// Client may expect mods.included and mods.excluded!
// On first install they are not defined.
@ -143,34 +226,73 @@
.every((dProp) => {
const ifDflt = (
!(dProp in mods) ||
Boolean(configs[dProp].dflt) === Boolean(mods[dProp])
!(
dProp in mods &&
Boolean(configs[dProp].dflt) !== Boolean(mods[dProp])
)
);
const ifMods = configs[dProp].ifDfltMods;
const ifMods = configs[dProp].ifDfltMods; // If default value implies PAC-script modification.
return ifDflt ? !ifMods : ifMods;
});
const self = {};
Object.assign(self, getDefaults(), mods);
const gdft = getDefaults();
Object.assign(self, gdft, mods);
self.ifNoMods = ifNoMods;
let customProxyArray = [];
if (self.customProxyStringRaw) {
customProxyArray = self.customProxyStringRaw
.replace(/#.*$/mg, '') // Strip comments.
.split( /(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g )
.split( /(?:\s*(?:;\r?\n)+\s*)+/g )
.map( (p) => p.trim() )
.filter( (p) => p && /\s+/g.test(p) );
.filter( (p) => p && /\s+/g.test(p) ); // At least one space is required.
if (self.ifUseSecureProxiesOnly) {
customProxyArray = customProxyArray.filter( (pStr) => /^HTTPS\s/.test(pStr) );
}
}
if (self.ifUseLocalWarp) {
self.warpPoints = ['SOCKS5 localhost:40000', 'HTTPS localhost:40000'];
customProxyArray.push(...self.warpPoints);
}
if (self.ifUseLocalTor) {
self.torPoints = ['SOCKS5 localhost:9150', 'SOCKS5 localhost:9050'];
customProxyArray.push(...self.torPoints);
}
// Hanlde protected proxies in customProxyArray.
const protectedProxies = [];
customProxyArray = customProxyArray.map((proxyScheme) => {
if (proxyScheme.includes('@')) {
const proxy = window.utils.parseProxyScheme(proxyScheme);
protectedProxies.push(proxy);
return `${proxy.type} ${proxy.hostname}:${proxy.port}`;
}
return proxyScheme;
});
if (!ifAuthSupported && protectedProxies.length) {
return [new Error('Запароленные прокси не поддерживаются в данной версии/платформе!')];
}
proxyHostToCredsList = {};
protectedProxies.forEach(({ hostname, port, username, password }) => {
proxyHostToCredsList[`${hostname}:${port}`] =
proxyHostToCredsList[`${hostname}:${port}`] || [];
const tries = proxyHostToCredsList[`${hostname}:${port}`];
tries.push({
username: username || '',
password: password || '',
});
});
self.filteredCustomsString = '';
if (customProxyArray.length) {
self.customProxyArray = customProxyArray;
@ -198,7 +320,8 @@
self.included = [];
self.excluded = [];
for(const host of Object.keys(self.exceptions)) {
if (self.exceptions[host]) {
const ifProxy = self.exceptions[host] || false;
if (ifProxy) {
self.included.push(host);
} else {
self.excluded.push(host);
@ -207,9 +330,9 @@
['included', 'excluded'].forEach((who) => {
self[who] = self[who]
.map( (s) => s.split('').reverse() )
.map( (domain) => domain.split('').reverse() )
.sort()
.map( (a) => a.reverse().join('') );
.map( (rDomain) => rDomain.reverse().join('') );
});
if (self.included.length && !self.filteredCustomsString) {
@ -225,29 +348,50 @@
window.apis.pacKitchen = {
getPacMods: getCurrentConfigs,
getPacModsRaw: () => getCurrentConfigs(true),
getOrderedConfigs: getOrderedConfigsForUser,
cook(pacData, pacMods = mandatory()) {
pacData = pacData.replace(
new RegExp(kitchenStartsMark + '[\\s\\S]*$', 'g'),
''
);
/a/.test('a'); // GC RegExp.input and friends.
return pacMods.ifNoMods ? pacData : pacData + `${ kitchenStartsMark }
/******/
/******/;+function(global) {
/******/;(function(global) {
/******/ "use strict";
/******/
/******/ const originalFindProxyForURL = FindProxyForURL;
/******/ global.FindProxyForURL = function(url, host) {
/******/
/******/ let tmp = function(url, host) {
/******/ const dotHost = '.' + host;
${
function() {
let generatedPac = `
/******/ if (${pacMods.ifMindWhitelist && pacMods.whitelist.length}) {
/******/ const ifWhitelisted =
/******/ ${JSON.stringify(pacMods.whitelist)}.some((whiteHost) => {
/******/ const ifWild = whiteHost.startsWith('*');
/******/ if (ifWild) {
/******/ return dotHost.endsWith(whiteHost.substr(1));
/******/ }
/******/ return host === whiteHost;
/******/ })
/******/ if (!ifWhitelisted) {
/******/ return 'DIRECT';
/******/ }
/******/ }`;
let res = pacMods.ifProhibitDns ? `
generatedPac += pacMods.ifProhibitDns ? `
/******/
/******/ global.dnsResolve = function(host) { return null; };
/******/
/******/` : '';
if (pacMods.ifProxyHttpsUrlsOnly) {
res += `
generatedPac += `
/******/
/******/ if (!url.startsWith("https")) {
/******/ return "DIRECT";
@ -257,7 +401,7 @@
}
if (pacMods.ifUseLocalTor) {
res += `
generatedPac += `
/******/
/******/ if (host.endsWith(".onion")) {
/******/ return "${pacMods.torPoints.join('; ')}";
@ -265,25 +409,25 @@
/******/
/******/ `;
}
res += `
generatedPac += `
/******/
/******/ const directIfAllowed = ${pacMods.ifProxyOrDie ? '""/* Not allowed. */' : '"; DIRECT"'};
/******/ const directIfAllowed = ${pacMods.ifProxyOrDie ? '""/* Not allowed. */' : '"DIRECT"'};
/******/`;
if (pacMods.filteredCustomsString) {
res += `
generatedPac += `
/******/
/******/ const filteredCustomProxies = "; ${pacMods.filteredCustomsString}";
/******/ const filteredCustomProxies = "${pacMods.filteredCustomsString}";
/******/`;
}
const ifIncluded = pacMods.included && pacMods.included.length;
const ifExcluded = pacMods.excluded && pacMods.excluded.length;
const ifManualExceptions = ifIncluded || ifExcluded;
const finalExceptions = {};
let finalExceptions = {};
if (pacMods.ifProxyMoreDomains) {
pacMods.moreDomains.reduce((acc, tld) => {
finalExceptions = pacMods.moreDomains.reduce((acc, tld) => {
acc[tld] = true;
acc['*.' + tld] = true;
return acc;
}, finalExceptions);
@ -294,21 +438,33 @@
const ifExceptions = Object.keys(finalExceptions).length;
if (ifExceptions) {
res += `
generatedPac += `
/******/
/******/ /* EXCEPTIONS START */
/******/ const dotHost = '.' + host;
/******/ const isHostInDomain = (domain) => dotHost.endsWith('.' + domain);
/******/ const domainReducer = (maxWeight, [domain, ifIncluded]) => {
// TODO: handle wildcards.
/******/ const isHostInDomain = (domain, ifWild) => {
if (ifWild) {
return dotHost.endsWith(domain.substr(1));
}
return domain === host;
}
/******/ const domainReducer = (maxWeight, [domain, ifProxy]) => {
/******/
/******/ if (!isHostInDomain(domain)) {
const ifWild = domain.startsWith('*.');
/******/ if (!isHostInDomain(domain, ifWild)) {
/******/ return maxWeight;
/******/ }
/******/ const newWeightAbs = domain.length;
let len = domain.length;
if (ifWild) {
len = len === 0 ? len : (len - 2)*2 - 1;
} else {
len = len*2;
}
/******/ const newWeightAbs = len;
/******/ if (newWeightAbs < Math.abs(maxWeight)) {
/******/ return maxWeight;
/******/ }
/******/ return newWeightAbs*(ifIncluded ? 1 : -1);
/******/ return newWeightAbs*(ifProxy ? 1 : -1);
/******/
/******/ };
/******/
@ -320,27 +476,30 @@
/******/ }
/******/ // Always proxy it!
${ pacMods.filteredCustomsString
? `/******/ return filteredCustomProxies + directIfAllowed;`
? `/******/ return filteredCustomProxies + "; " + directIfAllowed;`
: '/******/ /* No custom proxies -- continue. */'
}
/******/ }
/******/ /* EXCEPTIONS END */
`;
}
res += `
generatedPac += `
/******/ const pacScriptProxies = originalFindProxyForURL(url, host)${
/******/ pacMods.ifProxyOrDie ? '.replace(/DIRECT/g, "")' : ' + directIfAllowed'
/******/ pacMods.ifProxyOrDie
? '.replace(/DIRECT/g, "")'
: ' + "; " + directIfAllowed'
};`;
if(
!pacMods.ifUseSecureProxiesOnly &&
!pacMods.filteredCustomsString &&
pacMods.ifUsePacScriptProxies
) {
return res + `
/******/ return pacScriptProxies + directIfAllowed;`;
return generatedPac + `
/******/ return [pacScriptProxies, directIfAllowed]
.filter((p) => p).join("; ") || "DIRECT";`;
}
return res + `
return generatedPac + `
/******/ let pacProxyArray = pacScriptProxies.split(/(?:\\s*;\\s*)+/g).filter( (p) => p );
/******/ const ifNoProxies = pacProxyArray${pacMods.ifProxyOrDie ? '.length === 0' : '.every( (p) => /^DIRECT$/i.test(p) )'};
/******/ if (ifNoProxies) {
@ -348,6 +507,10 @@ ${ pacMods.filteredCustomsString
/******/ return "DIRECT";
/******/ }
/******/ return ` +
((pacMods.filteredCustomsString && !pacMods.ifUseOwnProxiesOnlyForOwnSites)
? 'filteredCustomProxies + "; " + '
: ''
) +
function() {
if (!pacMods.ifUsePacScriptProxies) {
@ -358,16 +521,57 @@ ${ pacMods.filteredCustomsString
filteredPacExp =
'pacProxyArray.filter( (pStr) => /^HTTPS\\s/.test(pStr) ).join("; ")';
}
return filteredPacExp + ' + ';
return filteredPacExp + ' + "; " + ';
}() + `${pacMods.filteredCustomsString ? 'filteredCustomProxies + ' : ''}directIfAllowed;`; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
}() + 'directIfAllowed;'; // Without DIRECT you will get 'PROXY CONN FAILED' pac-error.
}()
}
};
/******/ };
${
!pacMods.replaceDirectWith
? ''
: `
/******/ const oldTmp = tmp;
/******/ tmp = function(url, host) {
/******/ const ip = dnsResolve(host);
/******/ if (ip) {
/******/ const ipInt = convert_addr(ip);
/******/ if([
/******/ /* Reserved networks: https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv4 */
/******/ [-16777216, 0 ], // ['0.0.0.0' , '255.0.0.0' ],
/******/ [-16777216, 167772160 ], // ['10.0.0.0' , '255.0.0.0' ],
/******/ [-4194304, 1681915904 ], // ['100.64.0.0' , '255.192.0.0'],
/******/ [-16777216, 2130706432 ], // ['127.0.0.0' , '255.0.0.0' ],
/******/ [-65536, -1442971648], // ['169.254.0.0', '255.255.0.0'],
/******/ [-1048576, -1408237568], // ['172.16.0.0', '255.240.0.0'],
/******/ [-256, -1073741824], // ['192.0.0.0' , '255.255.255.0'],
/******/ [-256, -1073741312], // ['192.0.2.0' , '255.255.255.0'],
/******/ [-256, -1067949312], // ['192.88.99.0' , '255.255.255.0'],
/******/ [-65536, -1062731776], // ['192.168.0.0', '255.255.0.0'],
/******/ [-131072, -971898880 ], // ['198.18.0.0', '255.254.0.0'],
/******/ [-256, -969710592 ], // ['198.51.100.0', '255.255.255.0'],
/******/ [-256, -889163520 ], // ['203.0.113.0', '255.255.255.0'],
/******/ [-268435456, -536870912 ], // ['224.0.0.0', '240.0.0.0'],
/******/ [-268435456, -268435456 ], // ['240.0.0.0', '240.0.0.0'],
/******/ [-1, -1 ], // ['255.255.255.255' , '255.255.255.255'],
/******/ ].some(([netMask, maskedNet]) => (ipInt & netMask) === maskedNet)
/******/ ) {
/******/ return "DIRECT";
/******/ }
/******/ }
/******/ return oldTmp.call(this, url, host).replace(/(;|^)\\s*DIRECT\\s*(?=;|$)/g, "$1${pacMods.replaceDirectWith}");
/******/ };
`
}
/******/ if (global) {
/******/ global.FindProxyForURL = tmp;
/******/ } else {
/******/ FindProxyForURL = tmp;
/******/ }
}(this);`;
/*****/})(this);`;
},
@ -382,21 +586,15 @@ ${ pacMods.filteredCustomsString
details
? resolve(details)
: chrome.proxy.settings.get({}, timeouted(resolve) )
: chrome.proxy.settings.get({}, timeouted(resolve) ),
).then( (details) => {
).then((details) => {
if (
details.levelOfControl === 'controlled_by_this_extension'
details && details.levelOfControl === 'controlled_by_this_extension'
) {
const pac = window.utils.getProp(details, 'value.pacScript');
if (pac && pac.data) {
// Delete old kitchen modifications.
pac.data = pac.data.replace(
new RegExp(kitchenStartsMark + '[\\s\\S]*$', 'g'),
''
);
/a/.test('a'); // GC RegExp.input and friends.
return chrome.proxy.settings.set(details, chromified(cb));
}
}
@ -413,7 +611,7 @@ ${ pacMods.filteredCustomsString
checkIncontinence(details) {
if ( kitchenState(ifIncontinence) ) {
this.setNowAsync(details, () => {/* Swallow. */});
this.setNowAsync(details, (err) => { if (err) { throw err; } }); // TODO: suppress?
}
},
@ -448,9 +646,14 @@ ${ pacMods.filteredCustomsString
return cb(null, res, ...accWarns);
}
const newHosts = (pacMods.customProxyArray || []).map( (ps) => ps.split(/\s+/)[1] );
window.utils.fireRequest('ip-to-host-replace-all', newHosts, (err, res, ...moreWarns) => cb( err, res, ...accWarns.concat(moreWarns) ));
window.utils.fireRequest(
'ip-to-host-replace-all',
newHosts,
(err, res, ...moreWarns) =>
cb(err, res, ...accWarns, ...moreWarns),
);
}
},
);
},
@ -470,27 +673,21 @@ ${ pacMods.filteredCustomsString
const originalSet = chrome.proxy.settings.set.bind( chrome.proxy.settings );
chrome.proxy.settings.set = function(details, cb) {
const pac = window.utils.getProp(details, 'value.pacScript');
if (!(pac && pac.data)) {
return originalSet(details, cb);
return originalSet(details, window.utils.timeouted(cb));
}
const pacMods = getCurrentConfigs();
pac.data = pacKitchen.cook( pac.data, pacMods );
originalSet({value: details.value}, (/* No args. */) => {
originalSet({value: details.value}, window.utils.chromified((err) => {
kitchenState(ifIncontinence, null);
if (!err) {
kitchenState(ifIncontinence, null);
}
window.utils.lastError = err;
cb && cb();
});
}));
};
pacKitchen.checkIncontinence();
chrome.proxy.settings.onChange.addListener(
timeouted(
pacKitchen.checkIncontinence.bind(pacKitchen)
)
);
} // Private namespace ends.

View File

@ -19,14 +19,25 @@
*/
/*
Due to History
- *Async suffix usually means that function requires a cb.
It may not be related to async (returning a Promise).
This naming is confusing and should be reconsidered.
*/
{ // Private namespace starts.
const ifRu = chrome.i18n.getMessage('@@ui_locale').startsWith('ru');
console.log('Russian?', ifRu);
const mandatory = window.utils.mandatory;
const throwIfError = window.utils.throwIfError;
const chromified = window.utils.chromified;
const timeouted = window.utils.timeouted;
const clarifyThen = window.apis.errorsLib.clarifyThen;
const clarify = window.apis.errorsLib.clarify;
const Warning = window.apis.errorsLib.Warning;
const httpLib = window.apis.httpLib;
@ -49,8 +60,70 @@
};
const tryPromiseSeveralTimesAsync = (createPromise, timeoutsInSec) =>
createPromise().then(
(res) => Promise.resolve(res),
(err) => {
console.log('Promise failed, are there any retries?');
const outSec = timeoutsInSec.shift();
if (outSec === undefined) {
console.log('No retries left.');
return Promise.reject(err);
}
console.log('Retrying in', outSec, 'sec');
/*
const alarmName = 'try-promise=several-times-async';
const res = new Promise((resolve) => {
chrome.alarms.onAlarm.addListener((alarmInfo) => {
if (alarmInfo.name === alarmName) {
console.log('Time to retry.');
resolve(tryPromiseSeveralTimesAsync(createPromise, timeoutsInSec));
}
});
});
chrome.alarms.create(alarmName, { delayInMinutes: outSec/60 });
return res;
*/
return new Promise((resolve) =>
window.setTimeout(() => resolve(tryPromiseSeveralTimesAsync(createPromise, timeoutsInSec)), outSec*1000),
);
},
);
const doWithoutProxyAsync = (createPromise) => new Promise((resolve, reject) => {
console.log('Doing without proxy...');
chrome.proxy.settings.get({}, chromified((getErr, settings) => {
if (getErr) {
reject(getErr);
return;
}
const ifWeAreInControl = window.utils.areSettingsControlledFor(settings);
if (!ifWeAreInControl) {
resolve(createPromise());
return;
}
delete settings.levelOfControl;
const setProxyAsync = () => new Promise((setResolve, setReject) => {
console.log('Restoring chrome proxy settings...');
chrome.proxy.settings.set(
settings,
chromified((err) => err ? setReject(err) : setResolve()),
);
});
console.log('Clearing chrome proxy settings...');
chrome.proxy.settings.clear({}, chromified((clearErr) => {
if (clearErr) {
reject(clearErr);
return;
}
createPromise().then((actionResult) => setProxyAsync().then(() => resolve(actionResult)), reject);
}));
}));
});
const setPacAsync = function setPacAsync(
pacData = mandatory(), cb = throwIfError
pacData = mandatory(), cb = throwIfError,
) {
const config = {
@ -61,9 +134,16 @@
},
};
console.log('Setting chrome proxy settings...');
chrome.proxy.settings.set( {value: config}, chromified((err) => {
chrome.proxy.settings.set( { value: config }, chromified((err) => {
if (err) {
if (err.message === 'proxy.settings requires private browsing permission.') {
clarifyThen(
chrome.i18n.getMessage('AllowExtensionToRunInPrivateWindows'),
cb,
)(err);
return;
}
return cb(err);
}
handlers.updateControlState( () => {
@ -72,17 +152,16 @@
console.warn('Failed, other extension is in control.');
return cb(
new Error( window.utils.messages.whichExtensionHtml() )
new Error( window.utils.messages.whichExtensionHtml() ),
);
}
console.log('Successfuly set PAC in proxy settings..');
console.log('Successfuly set PAC in proxy settings.');
cb();
});
}));
};
const updatePacProxyIps = function updatePacProxyIps(
@ -91,75 +170,86 @@
cb = asyncLogGroup(
'Getting IPs for PAC hosts...',
cb
cb,
);
window.utils.fireRequest('ip-to-host-update-all', cb);
};
const setPacScriptFromProviderAsync = function setPacScriptFromProviderAsync(
provider, lastModifiedStr = mandatory(), cb = throwIfError
provider, lastModifiedStr, ifUnattended = mandatory(), cb = throwIfError,
) {
const pacUrl = provider.pacUrls[0];
cb = asyncLogGroup(
'Getting PAC script from provider...', pacUrl,
cb
cb,
);
httpLib.ifModifiedSince(pacUrl, lastModifiedStr, (err, newLastModifiedStr) => {
const warnings = [];
const originalCb = cb;
cb = (err, res, ...warns) => originalCb(err, res, ...warns, ...warnings);
const addWarning = (wText) => { warnings.push(new Warning(wText)) };
if (!newLastModifiedStr) {
const res = {lastModified: lastModifiedStr};
const ifWasEverModified = lastModifiedStr !== new Date(0).toUTCString();
if (ifWasEverModified) {
return cb(
null, res,
new Warning(
'Ваш PAC-скрипт не нуждается в обновлении. Его дата: ' +
lastModifiedStr
)
);
}
if (provider.distinctKey === 'Anticensority') {
const pacMods = window.apis.pacKitchen.getPacMods();
if (!pacMods.filteredCustomsString) {
addWarning(
ifRu
? \`
Не найдено СВОИХ прокси. Этот PAC-скрипт
работает только со <a href="https://git.io/ac-own-proxy">СВОИМИ прокси</a>
(по умолчанию будет использоваться локальный <a href="https://git.io/ac-tor">Tor</a>).
\`
: \`
Couldn't find OWN proxies. This PAC-script
works only with <a href="https://git.io/ac-own-proxy">OWN proxies</a>
(by default local <a href="https://git.io/ac-tor">Tor</a> will be used).
\`,
);
}
}
doWithoutProxyAsync(
// Employ all urls, the latter are fallbacks for the former.
const pacDataPromise = provider.pacUrls.reduce(
(promise, url) => promise.catch(
() => new Promise(
(resolve, reject) => httpLib.get(
url,
(newErr, pacData) => newErr ? reject(newErr) : resolve(pacData)
)
)
),
Promise.reject()
);
pacDataPromise.then(
(pacData) => {
setPacAsync(
pacData,
(err, res) => cb(
() => {
const tryAllUrlsAsync = () => provider.pacUrls.reduce(
(promise, url) => promise.catch(
() => new Promise(
(resolve, reject) => httpLib.get(
url,
(newErr, pacData) =>
newErr ? reject(newErr) : resolve(pacData),
),
),
),
Promise.reject(),
);
return (ifUnattended
? tryPromiseSeveralTimesAsync(tryAllUrlsAsync, [20, 40, 60])
: tryAllUrlsAsync()
).catch(
(err) => Promise.reject(clarify(
err,
Object.assign(res || {}, {lastModified: newLastModifiedStr})
)
);
},
clarifyThen(
'Не удалось скачать PAC-скрипт с адресов: [ '
+ provider.pacUrls.join(' , ') + ' ].',
cb
)
);
});
chrome.i18n.getMessage('FailedToDownloadPacScriptFromAddresses') + ': [ '
+ provider.pacUrls.join(' , ') + ' ].',
)),
);
},
).then(
(pacData) => {
setPacAsync(
pacData,
(err, res) => cb(
err,
Object.assign(res || {}, {lastModified: lastModifiedStr}),
),
);
},
cb,
);
};
window.apis.antiCensorRu = {
@ -168,20 +258,45 @@
pacProviders: {
Антизапрет: {
label: 'Антизапрет',
desc: \`Альтернативный PAC-скрипт от стороннего разработчика.
Работает быстрее, но охватывает меньше сайтов.
Блокировка определяется по доменному имени,
<br/> <a href="https://antizapret.prostovpn.org">Страница проекта</a>.\`,
// Distinct keys are needed if you want to check if a given
// provider is this or that (distinct it from others).
distinctKey: 'Antizapret',
label: chrome.i18n.getMessage('Antizapret'),
desc: ifRu
? \`Основной PAC-скрипт от автора проекта «Антизапрет».
Охватывет меньше сайтов.
Блокировка определяется по доменному имени и при необходимости по IP.
<br/> <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/PAC-скрипты:-различия">Сравнение PAC-скриптов</a>.
\`
: \`The main PAC-script from the author of project "Antizapret"\.
Covers fewer sites.
Block is detected based on a domain name and, if necessary, on an IP.
<br/> <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/PAC-скрипты:-различия">Comparison of PAC-scripts (ru)</a>.
\`,
order: 0,
pacUrls: ['https://antizapret.prostovpn.org/proxy.pac'],
pacUrls: [
'https://e.cen.rodeo:8443/proxy.pac',
'https://antizapret.prostovpn.org:8443/proxy.pac',
'https://antizapret.prostovpn.org:18443/proxy.pac',
'https://antizapret.prostovpn.org/proxy.pac',
],
},
Антицензорити: {
label: 'Антицензорити',
desc: \`Основной PAC-скрипт от автора расширения.
Работает медленней, но охватывает больше сайтов.
Блокировка определятся по доменному имени или IP адресу.<br/>
<a href="https://rebrand.ly/ac-anticensority">Страница проекта</a>.\`,
distinctKey: 'Anticensority',
label: chrome.i18n.getMessage('Anticensority'),
desc: ifRu
? \`Альтернативный PAC-скрипт от автора расширения.
Охватывает больше сайтов.
Блокировка определятся по доменному имени или IP адресу.
Подходит для провайдеров, блокирующих все сайты на одном IP.
<br/> <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/PAC-скрипты:-различия">Сравнение PAC-скриптов</a>.
\`
: \`Alternative PAC-script from the author of this extension.
Covers more sites.
Block is detected based on a domain name and on an IP address.
Better fits providers that block all sites on one IP.
<br/> <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/PAC-скрипты:-различия">Comparison of PAC-scripts (ru)</a>.
\`,
order: 1,
/*
@ -190,28 +305,17 @@
Version: 0.17
*/
pacUrls: ${JSON.stringify(anticensorityPacUrls, null, 2)},
/*[
// First official, shortened:
'https://rebrand.ly/ac-chrome-anticensority-pac',
// Second official, Cloud Flare with caching:
'https://anticensority.tk/generated-pac-scripts/anticensority.pac',
// GitHub.io (anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
// GitHub repo (anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
// Old, deprecated:
'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac',
// Google Drive (0.17, anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x32\x6d\x68\x42\x67\x46\x6e\x66\x34\x70\x45\x4c\x56\x6c\x47\x4e\x54\x42\x45\x4d\x58\x4e\x6d\x52\x58\x63',
],*/
},
onlyOwnSites: {
label: 'Только свои сайты и свои прокси',
desc: 'Проксируются только добавленные вручную сайты через СВОИ вручную добавленные прокси или через локальный Tor.',
distinctKey: 'onlyOwnSites',
label: chrome.i18n.getMessage('Only_own_sites_and_only_own_proxies'),
desc: ifRu
? 'Проксируются только добавленные вручную адреса через СВОИ вручную добавленные прокси или через локальный Tor.'
: 'Only added manually urls are proxied via your OWN manually added proxies or via Tor.',
order: 99,
pacUrls: [
'data:application/x-ns-proxy-autoconfig,' + escape('function FindProxyForURL(){ return "DIRECT"; }'),
]
],
}
},
@ -221,12 +325,18 @@
},
_currentPacProviderKey: 'Антицензорити',
_currentPacProviderKey: 'Антизапрет',
/* Is it the first time extension installed?
Do something, e.g. initiate PAC sync.
*/
ifFirstInstall: false,
/* We have .lastPacUpdateStamp and ._currentPacProviderLastModified.
LastModified is received from a server, we kind of don't trust it,
just use it for cache and maybe show to the user.
UpdateStamp is got from client and we base our timers on it,
malicious server can't interfere with it.
*/
lastPacUpdateStamp: 0,
setTitle() {
@ -234,12 +344,12 @@
const upDate = new Date(this.lastPacUpdateStamp).toLocaleString('ru-RU')
.replace(/:\\d+$/, '').replace(/\\.\\d{4}/, '');
chrome.browserAction.setTitle({
title: \`Обновлялись \${upDate} | Версия \${window.apis.version.build}\`,
title: \`\${chrome.i18n.getMessage('Updated')} \${upDate} | \${chrome.i18n.getMessage('Version')} \${window.apis.version.build}\`,
});
},
_currentPacProviderLastModified: 0, // Not initialized.
_currentPacProviderLastModified: 0,
getLastModifiedForKey(key = mandatory()) {
@ -272,7 +382,7 @@
setCurrentPacProviderKey(
newKey = mandatory(),
lastModified = new Date().toUTCString()
lastModified = new Date().toUTCString(),
) {
this.mustBeKey(newKey);
@ -309,27 +419,28 @@
}
}
chrome.storage.local.clear(
chrome.storage.local.remove(
'antiCensorRu',
() => chrome.storage.local.set(
onlySettable,
chromified(cb)
)
{ antiCensorRu: onlySettable },
chromified(cb),
),
);
},
syncWithPacProviderAsync(
key = this.currentPacProvierKey, cb = throwIfError) {
if( typeof(key) === 'function' ) {
cb = key;
key = this.getCurrentPacProviderKey();
syncWithPacProviderAsync(opts = {}, cb = throwIfError) {
const optsDefaults = Object.freeze({ key: this.getCurrentPacProviderKey(), ifUnattended: false });
if( typeof(opts) === 'function' ) {
cb = opts;
opts = {};
}
let { key, ifUnattended } = { ...optsDefaults, ...opts };
cb = asyncLogGroup('Syncing with PAC provider ' + key + '...', cb);
if (key === null) {
// No pac provider set.
return clarifyThen('Сперва выберите PAC-провайдера.', cb);
return clarifyThen(chrome.i18n.getMessage('ChoosePacProviderFirstD'), cb);
}
const pacProvider = this.getPacProvider(key);
@ -338,6 +449,7 @@
(resolve, reject) => setPacScriptFromProviderAsync(
pacProvider,
this.getLastModifiedForKey(key),
ifUnattended,
(err, res, ...warns) => {
if (!err) {
@ -354,24 +466,37 @@
)
);
const ipsErrorPromise = new Promise(
const updateIpsAsync = () => new Promise(
(resolve, reject) => updatePacProxyIps(
resolve
)
(err, res, ...warns) => {
if (err) {
reject([err, ...warns]);
return;
}
resolve([err, res, ...warns]);
},
),
);
Promise.all([pacSetPromise, ipsErrorPromise]).then(
([[pacErr, pacRes, ...pacWarns], ipsErr]) => {
const ipsPromise = !ifUnattended
? updateIpsAsync()
: tryPromiseSeveralTimesAsync(updateIpsAsync, [20, 40, 60]);
if (pacErr && ipsErr) {
Promise.all([pacSetPromise, ipsPromise]).then(
([[pacErr, pacRes, ...pacWarns], [ipsErr, ipsRes, ...ipsWarns]]) => {
if (pacErr) {
return cb(pacErr, pacRes);
}
const warns = pacWarns;
if (ipsErr) {
warns.push(ipsErr);
}
if (ipsWarns.length) {
warns.push(...ipsWarns);
}
this.pushToStorageAsync(
(pushErr) => cb(pacErr || pushErr, null, ...warns)
(pushErr) => cb(pacErr || pushErr, null, ...warns),
);
},
@ -398,7 +523,7 @@
console.log(
'Next PAC update is scheduled on',
new Date(nextUpdateMoment).toLocaleString('ru-RU')
new Date(nextUpdateMoment).toLocaleString('ru-RU'),
);
chrome.alarms.create(
@ -421,7 +546,7 @@
throw new Error('Key must be defined.');
}
if (this.currentProviderKey !== key) {
return this.syncWithPacProviderAsync(key, cb);
return this.syncWithPacProviderAsync({ key }, cb);
}
console.log(key + ' already installed.');
cb();
@ -441,11 +566,11 @@
}
this.setCurrentPacProviderKey(null);
this.pushToStorageAsync(
() => handlers.updateControlState(cb)
() => handlers.updateControlState(cb),
);
})
)
}),
),
);
},
@ -453,12 +578,25 @@
};
// ON EACH LAUNCH, STARTUP, RELOAD, UPDATE, ENABLE
chrome.storage.local.get(null, chromified( async (err, oldStorage) => {
if (err) {
throw err;
(async () => {
let ifConsentGiven = await window.utils.promisedLocalStorage.get('ifConsentGiven');
if (!ifConsentGiven) {
window.utils.openAndFocus('/pages/consent/index.html');
await window.apis.consent.promise;
ifConsentGiven = true
await window.utils.promisedLocalStorage.set({ ifConsentGiven });
}
let oldAntiCensorRu = await window.utils.promisedLocalStorage.get('antiCensorRu') || {};
const otherKeys = [
'pac-kitchen-if-incontinence',
'pac-kitchen-mods',
'ip-to-host',
'handlers-pac-error',
'handlers-ext-error',
'handlers-no-control',
];
/*
Event handlers that ALWAYS work (even if installation is not done
or failed).
@ -473,9 +611,9 @@
if (alarm.name === antiCensorRu._periodicUpdateAlarmReason) {
console.log(
'Periodic PAC update triggered:',
new Date().toLocaleString('ru-RU')
new Date().toLocaleString('ru-RU'),
);
antiCensorRu.syncWithPacProviderAsync(() => {/* swallow */});
antiCensorRu.syncWithPacProviderAsync({ ifUnattended: true }, () => { /* Swallow. */ });
}
})
@ -492,28 +630,29 @@
console.log('Keep cooked...');
await new Promise((resolve) => window.apis.pacKitchen.keepCookedNowAsync(resolve));
console.log('Storage on init:', oldStorage);
antiCensorRu.ifFirstInstall = Object.keys(oldStorage).length === 0;
//console.log('Storage on init:', oldAntiCensorRu);
antiCensorRu.ifFirstInstall = Object.keys(oldAntiCensorRu).length === 0;
if (antiCensorRu.ifFirstInstall) {
// INSTALL
console.log('Installing...');
handlers.switch('on', 'ext-error');
return chrome.runtime.openOptionsPage();
chrome.runtime.openOptionsPage();
return;
}
// LAUNCH, RELOAD, UPDATE
// Use old or migrate to default.
antiCensorRu._currentPacProviderKey =
oldStorage._currentPacProviderKey || null;
oldAntiCensorRu._currentPacProviderKey || null;
antiCensorRu.lastPacUpdateStamp =
oldStorage.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp;
oldAntiCensorRu.lastPacUpdateStamp || antiCensorRu.lastPacUpdateStamp;
antiCensorRu._currentPacProviderLastModified =
oldStorage._currentPacProviderLastModified
oldAntiCensorRu._currentPacProviderLastModified
|| antiCensorRu._currentPacProviderLastModified;
console.log(
'Last PAC update was on',
new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU')
new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU'),
);
@ -525,34 +664,45 @@
Better on each launch then on each pull.
*/
await new Promise((resolve) => {
await new Promise(async (resolve) => {
const ifUpdating = antiCensorRu.version !== oldStorage.version;
const ifUpdating = antiCensorRu.version !== oldAntiCensorRu.version;
if (!ifUpdating) {
// LAUNCH, RELOAD, ENABLE
antiCensorRu.pacProviders = oldStorage.pacProviders;
antiCensorRu.pacProviders = oldAntiCensorRu.pacProviders;
console.log('Extension launched, reloaded or enabled.');
return resolve();
}
// UPDATE & MIGRATION
console.log('Updating from ', oldStorage.version, 'to', antiCensorRu.version);
const key = antiCensorRu._currentPacProviderKey;
if (oldStorage.version === ' 0.0.1.2') {
if (key !== null && key !== 'onlyOwnSites') {
antiCensorRu._currentPacProviderKey = 'Антицензорити';
}
}
antiCensorRu.pushToStorageAsync(() => {
const ifUpdatedCb = () => antiCensorRu.pushToStorageAsync(() => {
console.log('Extension updated.');
resolve();
});
console.log('Updating from', oldAntiCensorRu.version, 'to', antiCensorRu.version);
try {
if (window.apis.version.isLeq(oldAntiCensorRu.version, '0.0.1.62')) {
window.apis.antiCensorRu.pacProviders['Антизапрет'].pacUrls = [
'https://e.cen.rodeo:8443/proxy.pac',
'https://antizapret.prostovpn.org:8443/proxy.pac',
'https://antizapret.prostovpn.org:18443/proxy.pac',
'https://antizapret.prostovpn.org/proxy.pac',
];
console.log('Successfully updated to 0.0.1.63.');
}
} catch (e) {
// Log update error.
console.log('UPDATE ERROR:');
console.error(e);
}
ifUpdatedCb();
});
if (antiCensorRu.getPacProvider()) {
@ -575,6 +725,6 @@
* Add storage.lastPacUpdateStamp.
**/
}));
})();
}

View File

@ -13,7 +13,7 @@
order: 0,
},
hostTracker: {
googleCache: {
title: 'Из кэша Google',
getUrl: (blockedUrl) => 'http://webcache.googleusercontent.com/search?q=cache:' + blockedUrl,
order: 1,
@ -27,19 +27,19 @@
otherUnblock: {
title: 'Разблокировать по-другому',
getUrl: (blockedUrl) => ('https://rebrand.ly/ac-unblock#' + blockedUrl),
getUrl: (blockedUrl) => ('https://anticensority.github.io/unblock#' + blockedUrl),
order: 3,
},
antizapretInfo: {
title: 'Сайт в реестре блокировок?',
getUrl: (blockedUrl) => 'https://antizapret.info/index.php?search=' + new URL(blockedUrl).hostname,
getUrl: (blockedUrl) => 'https://reestr.rublacklist.net/?q=' + new URL(blockedUrl).hostname,
order: 4,
},
support: {
title: 'Документация / Помощь / Поддержка',
getUrl: (blockedUrl) => 'https://rebrand.ly/ac-wiki',
getUrl: (blockedUrl) => 'https://github.com/anticensority/runet-censorship-bypass/wiki',
order: 99,
},

View File

@ -0,0 +1,48 @@
# For Reviewers
## Prerequirements
* You need a globally installed `gulp-cli@3.0.0`.
See https://gulpjs.com/docs/en/getting-started/quick-start#install-the-gulp-command-line-utility.
* Node v21.7.3
* NPM 10.5.0
## Steps
Steps to reproduce the same zip:
```
npm ci
cd src/extension-common/pages/options/
npm ci
cd -
npm start
# See ./build/extension-full
cd ./build/extension-full
zip -r runet-censorship-bypass-full.zip ./*
```
## Minified Files
### Ace Editor
https://ace.c9.io -> https://github.com/ajaxorg/ace -> Building Ace -> "The ace-builds repository endeavours to maintain the latest build" -> https://github.com/ajaxorg/ace-builds/ -> Select tag of 1.2.5, open https://github.com/ajaxorg/ace-builds/tree/v1.2.5/src-min and download the files you want to check.
```
mkdir downloaded
cd downloaded
wget https://raw.githubusercontent.com/ajaxorg/ace-builds/v1.2.5/src-min/ace.js
wget https://raw.githubusercontent.com/ajaxorg/ace-builds/v1.2.5/src-min/ext-searchbox.js
wget https://raw.githubusercontent.com/ajaxorg/ace-builds/v1.2.5/src-min/mode-javascript.js
wget https://raw.githubusercontent.com/ajaxorg/ace-builds/v1.2.5/src-min/worker-javascript.js
downloaded$ for i in ./*; do md5sum "$i"; done
2b9a1157bb3ba711a0402b6751d9ac71 ./ace.js
1f73efaff2853571af0e701c5e9a15ee ./ext-searchbox.js
e5eebd85c4e66667c28f124e6a07e3ed ./mode-javascript.js
f0d1342102d16ab7abe319b2683d10ea ./worker-javascript.js
```
## PAC-Script AntiZapret
https://antizapret.prostovpn.org/proxy.pac (old) and https://e.cen.rodeo:8443/proxy.pac (new) are generated by https://bitbucket.org/anticensority/antizapret-pac-generator-light/, reviewers may find justifications related to this PAC-script in that repo.

View File

@ -1 +0,0 @@
Files of this directory must be copied into final build without modifications.

View File

@ -3,7 +3,7 @@
"message": "Runet Censorship Bypass${nameSuffixEn}"
},
"extDesc": {
"message": "Circumvent Russian Internet Censorship: https://rebrand.ly/ac-wiki"
"message": "Circumvent Russian Internet Censorship: https://git.io/ac-wiki"
},
"proxy": {
"message": "proxy"
@ -11,7 +11,133 @@
"noControl": {
"message": "Other extension controls proxy!"
},
"which": {
"WhichQ": {
"message": "Which?"
},
"update": {
"message": "update"
},
"UpdatingDDD": {
"message": "Updating..."
},
"UpdatedD": {
"message": "Updated."
},
"DisablingDDD": {
"message": "Disabling..."
},
"DisabledD": {
"message": "Disabled."
},
"InstallingDDD": {
"message": "Installing..."
},
"PacScriptWasInstalledD": {
"message": "PAC-script was installed."
},
"Version": {
"message": "Version"
},
"FullVersion": {
"message": "Full version"
},
"VersionForSlowMachines": {
"message": "Version for slow machines"
},
"FailedToDownloadPacScriptFromAddresses": {
"message": "Failed to download PAC-script from addresses"
},
"ChoosePacProviderFirstD": {
"message": "Choose PAC-provider first."
},
"ProblemsQ": {
"message": "Problems?"
},
"Finish": {
"message": "OK"
},
"Disable": {
"message": "Disable"
},
"Only_own_sites_and_only_own_proxies": {
"message": "Only own sites and only own proxies"
},
"Antizapret": {
"message": "Antizapret"
},
"Anticensority": {
"message": "Anticensority"
},
"PAC_script": {
"message": "PAC-script"
},
"Exceptions": {
"message": "Exceptions"
},
"Own_proxies": {
"message": "Own proxies"
},
"Modifiers": {
"message": "Modifiers"
},
"Notifications": {
"message": "Notifications"
},
"Error": {
"message": "Error"
},
"Non_critical_error": {
"message": "Non-critical error. Don't worry: it works"
},
"Donate": {
"message": "Donate"
},
"Updated": {
"message": "Updated"
},
"ago": {
"message": "ago"
},
"never": {
"message": "never"
},
"ms": {
"message": "ms"
},
"s": {
"message": "s"
},
"min": {
"message": "min"
},
"h": {
"message": "h"
},
"d": {
"message": "d"
},
"w": {
"message": "w"
},
"m": {
"message": "m"
},
"ProxyTheDomainNameBelowQ": {
"message": "Proxy the domain name below?"
},
"auto": {
"message": "auto"
},
"yes": {
"message": "yes"
},
"no": {
"message": "no"
},
"noOwnProxiesError": {
"message": "Proxying of OWN sites is possible only via OWN proxies. No own proxies found that satisfy your requirements."
},
"AllowExtensionToRunInPrivateWindows": {
"message": "For the extension to work it is required to allow it to run in private windows, see <a href='https://github.com/anticensority/runet-censorship-bypass/wiki/Как-разрешить-запуск-расширения-в-приватных-окнах-|-How-to-allow-extension-to-run-in-private-windows'>a HOWTO</a>."
}
}

View File

@ -3,7 +3,7 @@
"message": "Обход блокировок Рунета${nameSuffixRu}"
},
"extDesc": {
"message": "Обход интернет-цензуры в России: https://rebrand.ly/ac-wiki"
"message": "Обход интернет-цензуры в России: https://git.io/ac-wiki"
},
"proxy": {
"message": "прокси"
@ -11,7 +11,133 @@
"noControl": {
"message": "Другое расширение контролирует настройки прокси!"
},
"which": {
"WhichQ": {
"message": "Какое?"
},
"update": {
"message": "обновить"
},
"UpdatingDDD": {
"message": "Обновляем..."
},
"UpdatedD": {
"message": "Обновлено."
},
"DisablingDDD": {
"message": "Отключение..."
},
"DisabledD": {
"message": "Отключено."
},
"InstallingDDD": {
"message": "Установка..."
},
"PacScriptWasInstalledD": {
"message": "PAC-скрипт установлен."
},
"Version": {
"message": "Версия"
},
"FullVersion": {
"message": "Полная версия"
},
"VersionForSlowMachines": {
"message": "Версия для слабых машин"
},
"FailedToDownloadPacScriptFromAddresses": {
"message": "Не удалось скачать PAC-скрипт с адресов"
},
"ChoosePacProviderFirstD": {
"message": "Сперва выберите PAC-провайдера."
},
"ProblemsQ": {
"message": "Проблемы?"
},
"Finish": {
"message": "Готово"
},
"Disable": {
"message": "Отключить"
},
"Only_own_sites_and_only_own_proxies": {
"message": "Только свои сайты и свои прокси"
},
"Antizapret": {
"message": "Антизапрет"
},
"Anticensority": {
"message": "Антицензорити"
},
"PAC_script": {
"message": "PAC-скрипт"
},
"Exceptions": {
"message": "Исключения"
},
"Own_proxies": {
"message": "Свои прокси"
},
"Modifiers": {
"message": "Модификаторы"
},
"Notifications": {
"message": "Уведомления"
},
"Error": {
"message": "Ошибка"
},
"Non_critical_error": {
"message": "Некритичная ошибка. Всё хорошо, продолжаем работу"
},
"Donate": {
"message": "Поддержать"
},
"Updated": {
"message": "Обновлялись"
},
"ago": {
"message": "назад"
},
"never": {
"message": "никогда"
},
"ms": {
"message": "мс"
},
"s": {
"message": "с"
},
"min": {
"message": "мин"
},
"h": {
"message": "ч"
},
"d": {
"message": "дн"
},
"w": {
"message": " недель"
},
"m": {
"message": " месяцев"
},
"ProxyTheDomainNameBelowQ": {
"message": "Проксировать указанное доменное имя?"
},
"auto": {
"message": "авто"
},
"yes": {
"message": "да"
},
"no": {
"message": "нет"
},
"noOwnProxiesError": {
"message": "Проксировать СВОИ сайты можно только при наличии СВОИХ прокси. Нет своих прокси, удовлетворяющих вашим требованиям."
},
"AllowExtensionToRunInPrivateWindows": {
"message": "Для работы расширения необходимо разрешить запуск в приватных окнах, см. <a href='https://github.com/anticensority/runet-censorship-bypass/wiki/Как-разрешить-запуск-расширения-в-приватных-окнах-|-How-to-allow-extension-to-run-in-private-windows'>инструкции</a>."
}
}

View File

@ -6,15 +6,15 @@
"description": "__MSG_extDesc__",
"version": "0.0.${version}",
"icons": {
"128": "/icons/default-128.png"
"128": "icons/default-128.png"
},
"author": "ilyaigpetrov@gmail.com",
"homepage_url": "https://github.com/anticensorship-russia/chromium-extension",
"author": "anticensority+owners@googlegroups.com",
"permissions": [
"proxy"
, "alarms"
, "storage"
, "unlimitedStorage"
, "<all_urls>"
, "tabs"
, "contextMenus"
@ -22,14 +22,21 @@
${extra_permissions}
],
"minimum_chrome_version": "55.0.0.0",
"browser_specific_settings": {
"gecko": {
"strict_min_version": "91.1.0"
}
},
"background": {
${persistent}
"scripts": [
"00-init-apis.js"
${scripts_0x}
, "11-error-handlers-api.js"
, "12-errors-lib.js"
, "13-http-lib.js"
, "15-firefox-proxy-settings.js"
${scripts_2x}
, "35-pac-kitchen-api.js"
, "37-sync-pac-script-with-pac-provider-api.js"
@ -38,6 +45,7 @@
, "75-context-menus.js"
]
},
"browser_action": {
"default_title": "Этот сайт благословлён | Версия ${version + versionSuffix}",
"default_popup": "/pages/options/index.html"
@ -46,4 +54,5 @@
"page": "/pages/options/index.html",
"chrome_style": false
}
}

View File

@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<link rel="icon" type="image/x-icon" href="./ribbon-128.ico">
<meta charset="utf-8">
<title>Согласие на сбор данных / Data Collection Consent</title>
<style>
p, ol { font-size: 16px }
</style>
</head>
<body>
<div style="margin: 0 auto; max-width: 35rem; text-align: justify; font-family: sans-serif">
<img src="./ribbon-128.png">
<h1>Согласие на сбор данных / Data Collection Consent</h1>
<p>
Этот документ написан на двух языках. Английский предпочтительней.
</p>
<p>
This document is written in two languages. English is preferable.
</p>
<p>
Привет! На связи команда разработчиков браузерного расширения «Обход блокировок Рунета».
Вы либо только что установили расширение, либо только что обновились до новой версии.
По новым правилам мы <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Зачем-нам-согласие-со-сбором-данных%3F">должны</a>
получить от вас согласие на сбор ваших данных и передачу их
третьим лицам.
</p>
<p>
Hi! It's "Runet Censorship Bypass" browser extension developers team.
You have just installed the extension or just updated to a new version.
According to the new requirements we <a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Зачем-нам-согласие-со-сбором-данных%3F">have to</a> get your consent before collecting your data and
sharing it with 3rd parties.
</p>
<p>
Сообщаем вам, что после первого запуска расширения и при дальнейшем его использовании
настроенные в нём PAC-скрипты и прокси-сервера могут собирать или уже* собирают
некоторые ваши данные. Какие именно, зависит от выбранного вами поставщика этих ресурсов,
так что рекомендуем ознакомиться с их соответствующей политикой конфиденциальности (Privacy
Policy).
<br>
* Если вы установили и пользовалсись расширением уже некоторое время. Этого экрана согласия не
было в старых версиях.
</p>
<p>
We inform you that starting from the first launch of the extension and on further usage chosen
PAC-scripts and proxy-servers may collect or are already* collecting some of your data. Which
exactly depends on the chosen provider of these resources so we recommend you to get
acquainted with their corresponding Privacy Policy.
<br>
* If you have installed and have been using the extension for some time already. This consent
screen wasn't shown in the old versions.
</p>
<p>
При первом запуске и по умолчанию будут использоваться PAC-скрипт и встроенные в него
прокси-сервера, предоставляемые <a href="https://antizapret.prostovpn.org:8443">проектом
"АнтиЗапрет"</a>, — политику конфиденциальности этого решения см. в
<a href="https://antizapret.prostovpn.org:8443/faq.html">FAQ</a> под заголовком "Какие данные
собирает сервис и каким образом они используются?".
</p>
<p>
On the first launch and by default the PAC-script and its built-in proxy-servers provided by
<a href="https://antizapret.prostovpn.org:8443">project "AntiZapret" (RU)</a> will be used, —
see its Privacy Policy in
<a href="https://antizapret.prostovpn.org:8443/faq.html">the FAQ (RU)</a> under the title
"Какие данные собирает сервис и каким образом они используются?". Its translation to EN is
present in the Privacy Policy of the extension.
</p>
<p>
Политику конфиденциальности самого расширения см.
<a
href="https://github.com/anticensority/runet-censorship-bypass/wiki/Privacy-Policy-|-Политика-конфиденциальности"
>здесь (EN)</a>.
</p>
<p>
See the Privacy Policy of this extension
<a
href="https://github.com/anticensority/runet-censorship-bypass/wiki/Privacy-Policy-|-Политика-конфиденциальности"
>here</a>.
</p>
<p>
В расширении представлены кнопки / There are these buttons in the extension:
</p>
<ol>
<li>
"Через Google Translate" / "Via Google Translate"
</li><li>
"Из кэша Google" / "From Google Cache"
</li><li>
"Из архива archive.org" / "From archive.org archive"
</li><li>
"Разблокировать по-другому" / "Unblock another way"
</li><li>
"Сайт в реестре блокировок?" / "Is site in the registry of blockings?"
</li>
</ol>
<p>
Все эти кнопки передают URL-адрес текущей вкладки в соответствующие службы. /
All these buttons share URL-address of the current tab with corresponding services.
</p>
<button id="agreeBtn">Разрешаю собирать заявленные данные / Allow claimed data collection
</button>
<button id="rejectBtn">Нет, удалите расширение / No, delete this extension
</button>
</div>
<script src="./index.js"></script>
<script src="../lib/keep-links-clickable.js"></script>
</body>
</html>

View File

@ -0,0 +1,14 @@
'use strict';
chrome.runtime.getBackgroundPage( (backgroundPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(
window, 'CONSENT', () => {
agreeBtn.onclick = () => {
backgroundPage.apis.consent.give();
window.close();
}
rejectBtn.onclick = () =>
chrome.management.uninstallSelf();
},
),
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,60 +1,62 @@
'use strict';
const setStatusTo = (msg) => document.getElementById('status').innerHTML = msg;
chrome.runtime.getBackgroundPage((bgWin) => {
const red = (text) => '<span style="color: red">' + text + '</span>';
const setStatusTo = (msg) => document.getElementById('status').innerHTML = msg;
const editor = window.ace.edit('editor');
editor.getSession().setOptions({
mode: 'ace/mode/javascript',
useSoftTabs: true,
});
chrome.proxy.settings.onChange.addListener(
(details) => setStatusTo(red( details.levelOfControl + '!') )
);
function _read() {
chrome.proxy.settings.get({}, (details) => {
let control = details.levelOfControl;
if (control.startsWith('controlled_by_other')) {
control = red(control);
}
setStatusTo(control);
console.log(details);
const pac = details.value.pacScript;
const data = pac && pac.data || 'PAC скрипт не установлен.';
editor.setValue( data );
const red = (text) => '<span style="color: red">' + text + '</span>';
const editor = window.ace.edit('editor');
editor.getSession().setOptions({
mode: 'ace/mode/javascript',
useSoftTabs: true,
});
}
bgWin.chrome.proxy.settings.onChange.addListener(
(details) => setStatusTo(red( details.levelOfControl + '!') )
);
document.querySelector('#read-button').onclick = _read;
function _read() {
document.querySelector('#save-button').onclick = () => {
bgWin.chrome.proxy.settings.get({}, (details) => {
let control = details.levelOfControl;
if (control.startsWith('controlled_by_other')) {
control = red(control);
}
setStatusTo(control);
const pac = details.value.pacScript;
const data = pac && pac.data || 'PAC скрипт не установлен.';
editor.setValue( data );
});
}
document.querySelector('#read-button').onclick = _read;
document.querySelector('#save-button').onclick = () => {
const config = {
mode: 'pac_script',
pacScript: {
mandatory: false,
data: editor.getValue(),
},
};
bgWin.chrome.proxy.settings.set( {value: config}, () => alert('Saved!') );
const config = {
mode: 'pac_script',
pacScript: {
mandatory: false,
data: editor.getValue(),
},
};
chrome.proxy.settings.set( {value: config}, () => alert('Saved!') );
};
document.querySelector('#clear-button').onclick = () => {
document.querySelector('#clear-button').onclick = () => {
bgWin.chrome.proxy.settings.clear({}, () => {
chrome.proxy.settings.clear({}, () => {
alert('Cleared! Reading...');
_read();
alert('Cleared! Reading...');
_read();
});
});
};
};
})

View File

@ -17,7 +17,9 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
# Сначала идёт список проксируемых сайтов,
# затем ==== на отдельной строке,
# затем исключённые сайты.
# После ещё одной строки с ==== идёт белый список.
# Сортировка с конца строки.
# Адреса со звёздочками поддерживаются: *.kasparov.ru, например.
# ПРОКСИРОВАТЬ:
@ -26,7 +28,16 @@ ${(mods.included || []).join('\n')}
===============================
# НЕ ПРОКСИРОВАТЬ:
${(mods.excluded || []).join('\n')}`;
${(mods.excluded || []).join('\n')}
===============================
# БЕЛЫЙ СПИСОК
# Разрешить расширению работать только с этими адресами:
${(mods.whitelist || []).join('\n')}
`.trim();
status.innerText = 'Успешно загружено!';
@ -35,7 +46,7 @@ ${(mods.excluded || []).join('\n')}`;
saveBtn.onclick = function() {
let [proxyList, dontProxyList] = editor.value
let [proxyList, dontProxyList, whitelist] = editor.value
.trim()
.replace(/#.*/g, '')
.split(/=+/g)
@ -45,12 +56,14 @@ ${(mods.excluded || []).join('\n')}`;
.filter((host) => host)
)
dontProxyList = dontProxyList || [];
whitelist = whitelist || [];
const exceptions = {};
proxyList.forEach((host) => (exceptions[host] = true));
dontProxyList.forEach((host) => (exceptions[host] = false));
const mods = backgroundPage.apis.pacKitchen.getPacMods();
mods.exceptions = exceptions;
mods.whitelist = whitelist;
backgroundPage.apis.pacKitchen.keepCookedNowAsync(mods, (err) => {
if (!err) {
status.innerText = 'Успешно сохранено!';

View File

@ -16,7 +16,7 @@ Use only if really required because of performance penalty.
const location = ln.href;
ln.onclick = function() {
chrome.tabs.create({active: !this.dataset.inBg, url: location});
chrome.tabs.create({active: this.dataset.inBg === "false", url: location});
return false;
};

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html style="display: none; will-change: contents, display">
<html style="visibility: hidden; will-change: contents, visibility">
<head>
<meta charset="utf-8">
<title>Настройки</title>

View File

@ -1,25 +1,27 @@
{
"name": "hello-react",
"name": "options-page-builder",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"license": "GPLv3",
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-plugin-dynamic-import-webpack": "^1.0.1",
"babel-cli": "^6.26.0",
"babel-loader": "^7.1.5",
"babel-plugin-dynamic-import-webpack": "^1.1.0",
"babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.24.1",
"concat-stream": "^1.6.0",
"concat-stream": "^1.6.2",
"csjs-inject": "^1.0.1",
"flow-bin": "^0.45.0",
"gulp": "^4.0.2",
"inferno": "~3.2.0",
"inferno-component": "^3.1.2",
"inferno-create-element": "^3.1.2",
"webpack": "^2.5.1"
"inferno-component": "^3.10.1",
"inferno-create-element": "^3.10.1",
"webpack": "^5.82.0",
"webpack-cli": "^5.0.2"
},
"scripts": {
"check": "flow status",
"build:prod": "webpack --define process.env.NODE_ENV=\"'production'\" --env=prod",
"build:prod": "webpack --node-env=\"'production'\" --env=prod",
"build:dev:nocomp": "NODE_ENV=development webpack --define process.env.NODE_ENV=\"'development'\" --env=dev",
"build:dev": "NODE_ENV=development webpack --debug --define process.env.NODE_ENV=\"'development'\" --output-pathinfo --env=dev",
"gulp": "cd .. && npm run gulp",
@ -27,6 +29,6 @@
"start": "cd .. && npm start"
},
"dependencies": {
"babel-plugin-inferno": "^3.2.0"
"babel-plugin-inferno": "^3.5.1"
}
}

View File

@ -17,12 +17,15 @@ export default function getApp(theState) {
constructor(props) {
super(props);
const hash = window.location.hash.substr(1);
const hashParams = new URLSearchParams(hash);
const sanitizedUrl = theState.flags.ifOpenedUnsafely ? { hash: '', search: '' } : window.location;
const hashParams = new URLSearchParams(sanitizedUrl.hash.substr(1));
const searchParams = new URLSearchParams(sanitizedUrl.search.substr(1));
this.state = {
status: 'Загрузка...',
ifInputsDisabled: false,
hashParams: hashParams,
hashParams,
searchParams,
};
this.setStatusTo = this.setStatusTo.bind(this);
@ -47,7 +50,10 @@ export default function getApp(theState) {
this.setStatusTo(
<ol style="list-style-type: initial;">
{newsArr.map(([title, url]) => (<li><a href={url}>{title}</a></li>))}
{newsArr
.map(([title, url]) => (<li><a href={url}>{title}</a></li>))
.reverse() // News order.
}
</ol>
);
@ -59,16 +65,16 @@ export default function getApp(theState) {
const uiComEtag = 'ui-last-comments-etag';
const uiLastNewsArr = 'ui-last-news-arr';
const statusFromHash = this.state.hashParams.get('status');
if (statusFromHash) {
return this.setStatusTo(statusFromHash);
const statusFromUrl = this.state.searchParams.get('status');
if (statusFromUrl) {
return this.setStatusTo(statusFromUrl);
}
const comDate = localStorage[uiComDate];
const query = comDate ? `?since=${comDate}` : '';
const oldEtag = localStorage[uiComEtag];
const headers = {
'User-Agent': 'anticensorship-russia',
'User-Agent': 'https://github.com/anticensority/runet-censorship-bypass',
};
if (oldEtag) {
Object.assign(headers, {
@ -79,8 +85,9 @@ export default function getApp(theState) {
headers: new Headers(headers),
};
//const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`;
const ghUrl = `https://api.github.com/repos/anticensority/for-testing/issues/1/comments${query}`;
// I comment and uncomment this variable manually before release or build:
const ghUrl = `https://api.github.com/repos/anticensority/chromium-extension/issues/10/comments${query}`;
// const ghUrl = `https://api.github.com/repos/anticensority/for-testing/issues/1/comments${query}`;
const [error, comments, etag] = await fetch(
ghUrl,
@ -223,7 +230,10 @@ export default function getApp(theState) {
this.setStatusTo(
(<span>
<span style="color:red">
{err ? <span><span class="emoji">🔥</span> Ошибка!</span> : 'Некритичная oшибка.'}
{err
? <span><span class="emoji">🔥</span> {chrome.i18n.getMessage('Error')}!</span>
: `${chrome.i18n.getMessage('Non_critical_error')}.`
}
</span>
<br/>
<span style="font-size: 0.9em; color: darkred" dangerouslySetInnerHTML={{__html: messageHtml}}></span>
@ -256,7 +266,6 @@ export default function getApp(theState) {
this.setStatusTo(beforeStatus);
this.switchInputs('off');
operation((err, res, ...warns) => {
warns = warns.filter( (w) => w );
if (err || warns.length) {
this.showErrors(err, ...warns);

View File

@ -4,7 +4,7 @@ export default function getApplyMods(theState) {
const resetMods = function resetMods(props) {
const ifSure = props.bgWindow.confirm('Сбросиь все модификаторы и ИСКЛЮЧЕНИЯ?');
const ifSure = props.bgWindow.confirm('Сбросить все модификаторы и ИСКЛЮЧЕНИЯ?');
if (!ifSure) {
return false;
}

View File

@ -75,13 +75,18 @@ export default function getExcEditor(theState) {
constructor(props) {
super(props);
const trimmedInputValueOrSpace =
props.currentTab &&
props.currentTab.url &&
!props.currentTab.url.startsWith('chrome')
? '*.' + (new URL(props.currentTab.url).hostname.replace(/^www\./g, ''))
: '';
const pacMods = props.apis.pacKitchen.getPacMods();
this.state = {
trimmedInputValueOrSpace:
props.currentTab && !props.currentTab.url.startsWith('chrome') ? new URL(props.currentTab.url).hostname : '',
trimmedInputValueOrSpace,
sortedListOfOptions: this.modsToOpts(pacMods),
isHostHidden: {}
hostToIfHidden: {},
};
this.handleRadioClick = this.handleRadioClick.bind(this);
this.handleInputOrClick = this.handleInputOrClick.bind(this);
@ -91,11 +96,11 @@ export default function getExcEditor(theState) {
hideAllOptions() {
this.setState({
isHostHidden: this.state.sortedListOfOptions.reduce(
(isHostHidden, [excHost]) => {
hostToIfHidden: this.state.sortedListOfOptions.reduce(
(hostToIfHidden, [excHost]) => {
isHostHidden[excHost] = true;
return isHostHidden;
hostToIfHidden[excHost] = true;
return hostToIfHidden;
},
{}),
@ -105,7 +110,7 @@ export default function getExcEditor(theState) {
isHostValid(host) {
const ValidHostnameRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
const ValidHostnameRegex = /^(?:\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
if(!ValidHostnameRegex.test(host)) {
this.props.funs.showErrors(new TypeError('Должно быть только доменное имя, без протокола, порта и пути. Попробуйте ещё раз.'));
return false;
@ -137,7 +142,7 @@ export default function getExcEditor(theState) {
case 'this-no':
if (ifYesClicked && !pacMods.filteredCustomsString) {
this.props.funs.showErrors( new TypeError(
'Проксировать СВОИ сайты можно только при наличии СВОИХ прокси. Нет своих прокси, удовлетворяющих вашим требованиям.'
chrome.i18n.getMessage('noOwnProxiesError'),
));
return false;
}
@ -205,7 +210,9 @@ export default function getExcEditor(theState) {
const ifInit = !event;
const currentHost = ifTriangleClicked ? '' : (trimmedInput || (ifInit ? '' : ' '));
setInputValue(currentHost);
this.setState({trimmedInputValueOrSpace: currentHost});
this.setState({
trimmedInputValueOrSpace: currentHost,
});
// Episode 2.
@ -274,7 +281,7 @@ export default function getExcEditor(theState) {
})();
this.setState({
isHostHidden: hidden,
hostToIfHidden: hidden,
sortedListOfOptions: options,
});
@ -293,10 +300,10 @@ export default function getExcEditor(theState) {
return (
<section style="padding-bottom: 1em;">
<div>Проксировать указанный сайт?</div>
<div>{chrome.i18n.getMessage('ProxyTheDomainNameBelowQ')}</div>
<div id="exc-address-container">
<div id="exc-address" class={inputProxyingState !== undefined ? ( inputProxyingState === true ? scopedCss.ifYes : scopedCss.ifNo ) : ''}>
<span>*.</span><input placeholder="navalny.com" list="exc-list" id="exc-editor"
<input placeholder="*.navalny.com" list="exc-list" id="exc-editor"
value={this.state.trimmedInputValueOrSpace}
ref={(inputNode) => { this.rawInput = inputNode; }}
onKeyDown={this.handleKeyDown.bind(this)}
@ -316,9 +323,10 @@ export default function getExcEditor(theState) {
// 1. Option's value may be changed to hide it from the tooltip.
// 2. Space is used in matching so even an empty input (replaced with space) has tooltip with prompts.
const ifProxy = excState;
return <option
value={ this.state.isHostHidden[excHost] ? '\n' : excHost + ' ' }
label={ excState === true ? labelIfProxied : (excState === false ? labelIfNotProxied : labelIfAuto) }/>
value={ this.state.hostToIfHidden[excHost] ? '\n' : excHost + ' ' }
label={ ifProxy === true ? labelIfProxied : (ifProxy === false ? labelIfNotProxied : labelIfAuto) }/>
})
}
@ -327,19 +335,19 @@ export default function getExcEditor(theState) {
<li><input id="this-auto" type="radio" checked name="if-proxy-this-site" onClick={this.handleRadioClick}/>{' '}
<label for="this-auto">{/*<span class="emoji">🔄(looks fat)</span>*/}<svg
class="icon"
style="position: relative; top: 0.15em;"><use xlink:href="#iconLoopRound"></use></svg>&nbsp;авто</label>
style="position: relative; top: 0.15em;"><use xlink:href="#iconLoopRound"></use></svg>&nbsp;{chrome.i18n.getMessage('auto')}</label>
</li>
<li>
<input id="this-yes" type="radio" name="if-proxy-this-site" checked={inputProxyingState === true} onClick={this.handleRadioClick}/>
{' '}<label for="this-yes">
<span
class="emoji____buggy"
></span>&nbsp;да
></span>&nbsp;{chrome.i18n.getMessage('yes')}
</label>
</li>
<li>
<input id="this-no" type="radio" name="if-proxy-this-site" checked={inputProxyingState === false} onClick={this.handleRadioClick}/>
{' '}<label for="this-no"><span class="emoji"></span>&nbsp;нет</label></li>
{' '}<label for="this-no"><span class="emoji"></span>&nbsp;{chrome.i18n.getMessage('no')}</label></li>
</ol>
</section>
);

View File

@ -67,7 +67,7 @@ export default function getExceptions(theState) {
<InfoLi
type="checkbox"
conf={{
label: '<span>Собирать <a href="../errors-to-exc/index.html">последние ошибки</a> сайтов</span>',
label: '<span>Собирать <a data-in-bg="false" href="../errors-to-exc/index.html">последние ошибки</a> сайтов</span>',
key: 'lookupLastErrors',
desc: 'Собирать последние ошибки в запросах, чтобы вручную добавлять избранные из них в исключения.',
}}

View File

@ -1,7 +1,7 @@
import Inferno from 'inferno';
import css from 'csjs-inject';
export default function getFooter() {
export default function getFooter(theState) {
const scopedCss = css`
@ -17,23 +17,22 @@ export default function getFooter() {
`;
return function (props) {
return (props) => (
<div class="horPadded">
<section class={scopedCss.statusRow}>
<div class={scopedCss.status} style="will-change: contents">
{typeof(props.status) === 'string' ? <div dangerouslySetInnerHTML={{ __html: props.status }}></div> : props.status}
</div>
</section>
return (
<div class="horPadded">
<section class={scopedCss.statusRow}>
<div clss={scopedCss.status} style="will-change: contents">{props.status}</div>
</section>
<footer class={scopedCss.controlRow + ' horFlex nowrap'}>
<input type="button" value="Готово" disabled={props.ifInputsDisabled} onClick={() => window.close()} />
<a href="../troubleshoot/index.html">
Проблемы?
</a>
</footer>
</div>
);
};
<footer class={scopedCss.controlRow + ' horFlex nowrap'}>
<input type="button" value={chrome.i18n.getMessage('Finish')} disabled={props.ifInputsDisabled} style={{ display: theState.flags.ifInsideEdgeOptionsPage ? 'none' : 'initial' }} onClick={() => window.close()} />
<a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Поддержать">{chrome.i18n.getMessage('Donate')}</a>
<a data-in-bg="false" href="../troubleshoot/index.html">
{chrome.i18n.getMessage('ProblemsQ')}
</a>
</footer>
</div>
);
};

View File

@ -25,6 +25,9 @@ export default function getInfoLi() {
.infoRow {
position: relative;
}
.infoRow a {
text-decoration: underline;
}
.infoRow > input[type="checkbox"] {
position: relative;
top: -0.08em;
@ -49,7 +52,7 @@ export default function getInfoLi() {
position: absolute;
white-space: initial;
word-break: initial;
top: 100%;
/* top: 100%; Commented to get rid of bug when tooltip is placed below InfoLi children fields. */
left: 0;
right: 1em;
z-index: 1;

View File

@ -7,8 +7,10 @@ export default function getLastUpdateDate(theState) {
componentWillMount() {
this.onStorageChangedHandler = (changes) =>
changes.lastPacUpdateStamp.newValue && this.forceUpdate();
this.onStorageChangedHandler = (changes) => {
const ac = changes.antiCensorRu;
return ac && ac.newValue && ac.newValue.lastPacUpdateStamp && this.forceUpdate();
};
chrome.storage.onChanged.addListener( this.onStorageChangedHandler );
@ -22,17 +24,17 @@ export default function getLastUpdateDate(theState) {
getDate(antiCensorRu) {
let dateForUser = 'никогда';
let dateForUser = chrome.i18n.getMessage('never');
if( antiCensorRu.lastPacUpdateStamp ) {
let diff = Date.now() - antiCensorRu.lastPacUpdateStamp;
let units = 'мс';
let units = chrome.i18n.getMessage('ms');
const gauges = [
[1000, 'с'],
[60, 'мин'],
[60, 'ч'],
[24, 'дн'],
[7, ' недель'],
[4, ' месяцев'],
[1000, chrome.i18n.getMessage('s')],
[60, chrome.i18n.getMessage('min')],
[60, chrome.i18n.getMessage('h')],
[24, chrome.i18n.getMessage('d')],
[7, chrome.i18n.getMessage('w')],
[4, chrome.i18n.getMessage('m')],
];
for(const g of gauges) {
const diffy = Math.floor(diff / g[0]);
@ -41,10 +43,10 @@ export default function getLastUpdateDate(theState) {
diff = diffy;
units = g[1];
}
dateForUser = diff + units + ' назад';
dateForUser = diff + units + ' ' + chrome.i18n.getMessage('ago');
}
return {
text: `${dateForUser} / ${antiCensorRu.pacUpdatePeriodInMinutes/60}ч`,
text: `${dateForUser} / ${antiCensorRu.pacUpdatePeriodInMinutes/60}${chrome.i18n.getMessage('h')}`,
title: new Date(antiCensorRu.lastPacUpdateStamp).toLocaleString('ru-RU'),
};
@ -53,7 +55,7 @@ export default function getLastUpdateDate(theState) {
render(props) {
const date = this.getDate(props.apis.antiCensorRu);
return (<div>Обновлялись: <span class="updateDate" title={date.title}>{ date.text }</span></div>);
return (<div>{chrome.i18n.getMessage('Updated')}: <span class="updateDate" title={date.title}>{ date.text }</span></div>);
}

View File

@ -31,6 +31,7 @@ export default function getMain(theState) {
const Notifications = getNotifications(theState);
const checksName = 'pacMods';
let selection = [0, 0]; // TODO: dirty hack but seems ok.
return class Main extends Component {
@ -144,23 +145,43 @@ export default function getMain(theState) {
return createElement(TabPanel, Object.assign({}, props, {
tabs: [
{
label: 'PAC-скрипт',
label: chrome.i18n.getMessage('PAC_script'),
content: createElement(PacChooser, props),
key: 'pacScript',
},
{
label: 'Исключения',
label: chrome.i18n.getMessage('Exceptions'),
content: createElement(Exceptions, props),
key: 'exceptions',
},
{
label: 'Свои прокси',
label: chrome.i18n.getMessage('Own_proxies'),
content: createElement(
ModList,
Object.assign({}, props, {
orderedConfigs: this.state.catToOrderedMods['ownProxies'],
childrenOfMod: {
customProxyStringRaw: ProxyEditor,
replaceDirectWith: ({ conf, onNewValue, ifInputsDisabled }) =>
(<input
style="width: 100%; margin: 0.5em 0"
disabled={ifInputsDisabled}
value={conf.value || ''}
onInput={(event) => {
const t = event.target;
selection = [t.selectionStart, t.selectionEnd];
onNewValue(true, t.value);
}}
ref={(input) => {
if (input) {
input.focus();
input.selectionStart = selection[0];
input.selectionEnd = selection[1];
}
}}
/>),
},
name: checksName,
}, modsHandlers)
@ -168,7 +189,7 @@ export default function getMain(theState) {
key: 'ownProxies',
},
{
label: 'Модификаторы',
label: chrome.i18n.getMessage('Modifiers'),
content: createElement(
ModList,
Object.assign({}, props, {
@ -183,7 +204,7 @@ export default function getMain(theState) {
key: 'applyMods',
},
{
label: 'Уведомления',
label: chrome.i18n.getMessage('Notifications'),
content: createElement(Notifications, props),
key: 'notifications',
},

View File

@ -55,7 +55,14 @@ export default function getModList(theState) {
const child = ifMayHaveChild && this.state.checks[index]
&& createElement(
props.childrenOfMod[conf.key],
Object.assign({}, props, {conf, onNewValue: (ifValid, newValue) => this.handleNewValue(ifValid, confMeta, newValue)})
Object.assign(
{},
props,
{
conf,
onNewValue: (ifValid, newValue) => this.handleNewValue(ifValid, confMeta, newValue),
},
)
);
return (<InfoLi

View File

@ -55,16 +55,16 @@ export default function getPacChooser(theState) {
constructor(props) {
super();
super(props);
this.state = {
chosenPacName: 'none',
};
this.updatePac = function updatePac(onSuccess) {
props.funs.conduct(
'Обновляем...',
(cb) => props.apis.antiCensorRu.syncWithPacProviderAsync(cb),
'Обновлено.',
chrome.i18n.getMessage('UpdatingDDD'),
(cb) => theState.apis.antiCensorRu.syncWithPacProviderAsync(cb),
chrome.i18n.getMessage('UpdatedD'),
onSuccess
);
};
@ -75,7 +75,7 @@ export default function getPacChooser(theState) {
getCurrentProviderId() {
return this.props.apis.antiCensorRu.getCurrentPacProviderKey() || 'none';
return theState.apis.antiCensorRu.getCurrentPacProviderKey() || 'none';
}
@ -94,24 +94,24 @@ export default function getPacChooser(theState) {
const pacKey = event.target.id;
if (
pacKey === (
this.props.apis.antiCensorRu.getCurrentPacProviderKey() || 'none'
theState.apis.antiCensorRu.getCurrentPacProviderKey() || 'none'
)
) {
return false;
}
if (pacKey === 'none') {
this.props.funs.conduct(
'Отключение...',
(cb) => this.props.apis.antiCensorRu.clearPacAsync(cb),
'Отключено.',
chrome.i18n.getMessage('DisablingDDD'),
(cb) => theState.apis.antiCensorRu.clearPacAsync(cb),
chrome.i18n.getMessage('DisabledD'),
() => this.setState({ chosenPacName: 'none' }),
checkChosenProvider
);
} else {
this.props.funs.conduct(
'Установка...',
(cb) => this.props.apis.antiCensorRu.installPacAsync(pacKey, cb),
'PAC-скрипт установлен.',
chrome.i18n.getMessage('InstallingDDD'),
(cb) => theState.apis.antiCensorRu.installPacAsync(pacKey, cb),
chrome.i18n.getMessage('PacScriptWasInstalledD'),
checkChosenProvider
);
}
@ -124,10 +124,10 @@ export default function getPacChooser(theState) {
const iddyToCheck = this.getCurrentProviderId();
return (
<div>
{props.flags.ifInsideOptionsPage && (<header>PAC-скрипт:</header>)}
{props.flags.ifInsideOptionsPage && (<header>{chrome.i18n.getMessage('PAC_script')}:</header>)}
<ul>
{
[...props.apis.antiCensorRu.getSortedEntriesForProviders(), {key: 'none', label: 'Отключить'}].map((provConf) =>
[...theState.apis.antiCensorRu.getSortedEntriesForProviders(), {key: 'none', label: chrome.i18n.getMessage('Disable')}].map((provConf) =>
(<InfoLi
onClick={this.radioClickHandler}
conf={provConf}
@ -135,7 +135,7 @@ export default function getPacChooser(theState) {
name="pacProvider"
checked={iddyToCheck === provConf.key}
ifInputsDisabled={props.ifInputsDisabled}
nodeAfterLabel={<a href="" class={scopedCss.updateButton} onClick={this.updateClickHandler}>[обновить]</a>}
nodeAfterLabel={<a href="" class={scopedCss.updateButton} onClick={this.updateClickHandler}>[{chrome.i18n.getMessage('update')}]</a>}
/>)
)
}
@ -145,10 +145,10 @@ export default function getPacChooser(theState) {
<div class={scopedCss.fullLineHeight}>
{
props.flags.ifMini
? (<a class={scopedCss.otherVersion + ' emoji'} href="https://rebrand.ly/ac-versions"
title="Полная версия">🏋</a>)
: (<a class={scopedCss.otherVersion + ' emoji'} href="https://rebrand.ly/ac-versions"
title="Версия для слабых машин">🐌</a>)
? (<a class={scopedCss.otherVersion + ' emoji'} href="https://github.com/anticensority/runet-censorship-bypass/wiki/Различные-версии-расширения"
title={chrome.i18n.getMessage("FullVersion")}>🏋</a>)
: (<a class={scopedCss.otherVersion + ' emoji'} href="https://github.com/anticensority/runet-censorship-bypass/wiki/Различные-версии-расширения"
title={chrome.i18n.getMessage("VersionForSlowMachines")}>🐌</a>)
}
</div>
</div>
@ -159,7 +159,7 @@ export default function getPacChooser(theState) {
componentDidMount() {
if (this.props.apis.antiCensorRu.ifFirstInstall) {
if (theState.apis.antiCensorRu.ifFirstInstall) {
this.updatePac();
}

View File

@ -64,7 +64,7 @@ export default function getProxyEditor(theState) {
{
text-align: center;
}
table.editor tr.proxyRow input[name="hostname"] {
table.editor tr.proxyRow input[name="crededHostname"] {
padding: 0;
}
@ -158,8 +158,14 @@ export default function getProxyEditor(theState) {
return true;
};
const splitBySemi = (proxyString) => proxyString.replace(/#.*$/mg, '').trim().split(/\s*;\s*/g).filter((s) => s);
const joinBySemi = (strs) => strs.join(';\n') + ';';
const splitBySemi = (proxyString) => proxyString
.replace(/#.*$/mg, '')
.trim()
.split(/\s*;\r?\n\s*/g)
.map((s) => s.trim())
.filter((s) => s);
const joinBySemi = (strs) => strs.join(';\n');
const normalizeProxyString = (str) => joinBySemi(splitBySemi(str));
const PROXY_TYPE_LABEL_PAIRS = [['PROXY', 'PROXY/HTTP'],['HTTPS'],['SOCKS4'],['SOCKS5'],['SOCKS']];
@ -217,11 +223,11 @@ export default function getProxyEditor(theState) {
}, {});
const type = that.state.selectedNewType;
const hostname = elements.newHostname;
const crededHostname = elements.newHostname;
const port = elements.newPort;
const newValue = `${that.props.proxyStringRaw}; ${type} ${hostname}:${port}`
.trim().replace(/(\s*;\s*)+/, '; ');
const newValue = `${that.props.proxyStringRaw};\n${type} ${crededHostname}:${port}`
.trim().replace(/(\s*;\n\s*)+/, ';\n');
that.props.setProxyStringRaw(true, newValue);
}
@ -322,10 +328,17 @@ export default function getProxyEditor(theState) {
</tr>
{/* ADD NEW PROXY ENDS. */}
{
splitBySemi(this.props.proxyStringRaw).map((proxyAsString, index) => {
splitBySemi(this.props.proxyStringRaw).map((proxyAsStringRaw, index) => {
const proxyAsString = proxyAsStringRaw.trim();
const {
type,
creds,
hostname,
port,
} = theState.utils.parseProxyScheme(proxyAsString);
const [type, addr] = proxyAsString.trim().split(/\s+/);
const [hostname, port] = addr.split(':');
return (
<tr class={scopedCss.proxyRow}>
<td>
@ -335,7 +348,7 @@ export default function getProxyEditor(theState) {
>X</button>
</td>
<td>{type}</td>
<td><input value={hostname} name="hostname" readonly/></td>
<td><input value={`${creds && `${creds}@`}${hostname}`} name="crededHostname" readonly/></td>
<td>{port}</td>
<td>
<button type="button" disabled={props.ifInputsDisabled}
@ -350,6 +363,7 @@ export default function getProxyEditor(theState) {
}
</tbody>
</table>
<a href="https://github.com/anticensority/runet-censorship-bypass/wiki/Прокси-и-пароль">Запароленные прокси?</a>
</form>
);
}
@ -390,28 +404,34 @@ export default function getProxyEditor(theState) {
const errors = splitBySemi(this.state.stashedExports)
.map((proxyAsString) => {
const [rawType, addr, ...rest] = proxyAsString.split(/\s+/);
if (rest && rest.length) {
return new Error(
`"${rest.join(', ')}" кажется мне лишним. Вы забыли ";"?`
);
}
const {
type,
creds,
hostname,
port,
username,
password,
} = theState.utils.parseProxyScheme(proxyAsString);
const crededAddr = `${creds ? `${creds}@` : ''}${hostname}:${port}`;
const knownTypes = PROXY_TYPE_LABEL_PAIRS.map(([type, label]) => type);
if( !knownTypes.includes(rawType.toUpperCase()) ) {
if( !knownTypes.includes(type.toUpperCase()) ) {
return new Error(
`Неверный тип ${rawType}. Известные типы: ${knownTypes.join(', ')}.`
`Неверный тип ${type}. Известные типы: ${knownTypes.join(', ')}.`
);
}
if (!(addr && /^[^:]+:\d+$/.test(addr))) {
if (!(crededAddr && /^(?:.+@)?[^:]+:\d+$/.test(crededAddr))) {
return new Error(
`Адрес прокси "${addr || ''}" не соответствует формату "омен_или_IP>:<порт_из_цифр>".`
`Адрес прокси "${crededAddr || ''}" не соответствует формату "<опц_логин>:<опц_пароль>@омен_или_IP>:<порт_из_цифр>".`
);
}
const [hostname, rawPort] = addr.split(':');
const port = parseInt(rawPort);
if (port < 0 || port > 65535) {
if (password && !username) {
return new Error('Вашему пользователю не хватает имени?');
}
const portInt = parseInt(port);
if (portInt < 0 || portInt > 65535) {
return new Error(
`Порт "${rawPort}" должен быть целым числом от 0 до 65535.`
`Порт "${port}" должен быть целым числом от 0 до 65535.`
);
}
return false;
@ -495,7 +515,7 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()}
value={
this.state.stashedExports !== false
? this.state.stashedExports
: (this.props.proxyStringRaw || '').replace(/\s*;\s*/g, ';\n')
: (this.props.proxyStringRaw || '').replace(/\s*;\n\s*/g, ';\n')
}
/></td>
</tr>
@ -514,10 +534,12 @@ PROXY foobar.com:8080; # Not HTTP!`.trim()}
return proxyStringRaw
.replace(/#.*$/mg, '') // Strip comments.
.replace(/[^\S\r\n]*DIRECT[^\S\r\n]*/g, '') // Remove DIRECT from old versions.
/*
.split( /(?:[^\S\r\n]*(?:;|\r?\n)+[^\S\r\n]*)+/g )
.map( (p) => p.trim() )
.filter((p) => p)
.join(';\n');
*/
};

View File

@ -54,7 +54,7 @@ export default function getTabPannel({ flags, baseCss }) {
.navLabels {
background-color: var(--cr-grey-panel);
text-align: center;
min-width: 24em;
min-width: 25em;
}
.navLabels li label {
display: inline-block;

View File

@ -4,7 +4,7 @@ export default function append(document, { flags }) {
document.querySelector('style').innerHTML = `
/* GLOBAL VARIABLES */
:root {
body {
--ribbon-color: #4169e1;
--blue-bg: dodgerblue;
--default-grey: #bfbfbf;
@ -12,13 +12,13 @@ export default function append(document, { flags }) {
--cr-icon-selected: #d7d7d7;
--cr-popup-border: #bababa;
--cr-grey-panel: #f2f2f2;
${ flags.ifInsideOptionsPage ? '' : 'max-width: 24em;' }
}
/* BASE ELEMENTS */
body {
margin: 0;
max-width: 25em;
}
a, a:visited {
color: var(--ribbon-color);
@ -27,9 +27,11 @@ export default function append(document, { flags }) {
a:hover {
text-decoration: underline;
}
/*
label {
user-select: none;
}
*/
div, section, header, ul, ol {
margin: 0;
padding: 0;

View File

@ -9,7 +9,13 @@ import getApp from './components/App';
chrome.runtime.getBackgroundPage( (bgWindow) =>
bgWindow.apis.errorHandlers.installListenersOn(
window, 'PUP', async() => {
/*
`Extension context invalidated` error is thrown if `window.closed` is true and call to
`window.chrome.i18n` or other `window.chrome` api happens. Use bgWindow.chrome instead.
Use winChrome for tab-related calls like winChrome.tabs.getCurrent.
*/
window.winChrome = window.chrome;
window.chrome = bgWindow.chrome;
let theState;
{
const apis = bgWindow.apis;
@ -29,15 +35,26 @@ chrome.runtime.getBackgroundPage( (bgWindow) =>
// IF INSIDE OPTIONS TAB
const currentTab = await new Promise(
(resolve) => chrome.tabs.query(
(resolve) => winChrome.tabs.query(
{active: true, currentWindow: true},
([tab]) => resolve(tab)
([tab]) => resolve(tab),
)
);
// winChrome.runtime.sendMessage({ currentTab, eventName: 'POPUP_OPENED' });
theState.flags.ifInsideOptionsPage = !(currentTab && currentTab.url) || /.*:\/\/extensions\/\?options=/g.test(currentTab.url) || currentTab.url.startsWith('about:addons');
theState.flags.ifInsideEdgeOptionsPage = theState.flags.ifInsideOptionsPage && currentTab && currentTab.url && currentTab.url.startsWith('edge://');
theState.flags.ifInsideOptionsPage = !currentTab || currentTab.url.startsWith('chrome://extensions/?options=');
theState.currentTab = currentTab;
// If opened not via popup and not via options modal.
// E.g., if opened via copy-pasting an URL into the address bar from somewhere.
// If browser is not Chrome (Opera, e.g.) then options page may be opened in a separate tab
// and then you will get a false positive.
theState.flags.ifOpenedUnsafely = Boolean(await new Promise(
(resolve) => winChrome.tabs.getCurrent(resolve),
));
// STATE DEFINED, COMPOSE.
appendGlobalCss(document, theState);
@ -49,7 +66,13 @@ chrome.runtime.getBackgroundPage( (bgWindow) =>
);
// READY TO RENDER
document.documentElement.style.display = 'initial';
const show = () => { document.documentElement.style.visibility = 'initial'; };
if (theState.flags.ifInsideOptionsPage) {
show();
} else {
setTimeout(show, 200); // Mac bug: https://bugs.chromium.org/p/chromium/issues/detail?id=428044
}
}
)

View File

@ -5,17 +5,31 @@
<title>Устранение проблем</title>
</head>
<body>
<h1>Устранение проблем</h1>
<ol>
<li><a href id="view-errors">Детали последних ошибок</a></li>
<li><a href id="reset-settings">Сбросить настройки</a></li>
<li><a href="https://rebrand.ly/ac-support" target="_blank">Файл самопомощи</a></li>
<li><a href="https://rebrand.ly/ac-contact">Напишите нам!</a></li>
<li><a data-in-bg="false" href class="view-errors">Детали последних ошибок</a></li>
<li><a data-in-bg="false" href class="reset-settings">Сбросить настройки</a></li>
<li><a data-in-bg="false" href="https://github.com/anticensority/runet-censorship-bypass/wiki/Если-расширение-не-работает" target="_blank">Файл самопомощи</a></li>
<li><a data-in-bg="false" href="https://groups.google.com/g/anticensority">Напишите нам!</a></li>
</ol>
<h2>Для продвинутых</h2>
<ol>
<li><a href="https://rebrand.ly/ac-logs">Как прочитать логи?</a></li>
<li><a href="../debug/index.html">Отладка PAC-скрипта</a></li>
<li><a data-in-bg="false" href="https://github.com/anticensority/runet-censorship-bypass/wiki/Как-прочитать-логи%3F-%28для-продвинутых%29">Как прочитать логи?</a></li>
<li><a data-in-bg="false" href="../debug/index.html">Отладка PAC-скрипта</a></li>
</ol>
<hr/>
<h1>Troubleshooting</h1>
<ol>
<li><a data-in-bg="false" href class="view-errors">Details of last errors</a></li>
<li><a data-in-bg="false" href class="reset-settings">Reset settings</a></li>
<li><a data-in-bg="false" href="https://github.com/anticensority/runet-censorship-bypass/wiki/Если-расширение-не-работает" target="_blank">Troubleshoot guide (ru)</a></li>
<li><a data-in-bg="false" href="https://groups.google.com/g/anticensority">Write to us!</a></li>
</ol>
<h2>Advanced</h2>
<ol>
<li><a data-in-bg="false" href="https://github.com/anticensority/runet-censorship-bypass/wiki/Как-прочитать-логи%3F-%28для-продвинутых%29">How to read logs?</a></li>
<li><a data-in-bg="false" href="../debug/index.html">PAC-script debugging</a></li>
</ol>
<script src="./index.js"></script>
<script src="../lib/keep-links-clickable.js"></script>

View File

@ -4,15 +4,22 @@ chrome.runtime.getBackgroundPage( (backgroundPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(
window, 'TRBL', () => {
document.getElementById('reset-settings').onclick = () => {
document.querySelectorAll('.reset-settings').forEach((el) => {
backgroundPage.localStorage.clear();
chrome.storage.local.clear( () => chrome.runtime.reload() );
el.onclick = () => {
};
backgroundPage.localStorage.clear();
chrome.storage.local.clear( () => chrome.runtime.reload() );
document.getElementById('view-errors').onclick = () =>
backgroundPage.apis.errorHandlers.viewError('all');
};
});
})
document.querySelectorAll('.view-errors').forEach((el) => {
el.onclick = () =>
backgroundPage.apis.errorHandlers.viewError('all');
});
},
),
);

View File

@ -1,10 +1,10 @@
'use strict';
const Storage = require('_project-root/tools/sinon-storage');
const Storage = require('symlink-to/project-root/tools/sinon-storage');
const Chai = require('chai');
const Mocha = require('mocha');
const CachelessRequire = require('_project-root/tools/cacheless-require')(module);
const CachelessRequire = require('symlink-to/project-root/tools/cacheless-require')(module);
Mocha.describe('window.apis.pacKitchen', function () {

View File

@ -3,7 +3,7 @@
const Chai = require('chai');
const Mocha = require('mocha');
const CachelessRequire = require('_project-root/tools/cacheless-require')(module);
const CachelessRequire = require('symlink-to/project-root/tools/cacheless-require')(module);
Mocha.describe('window.utils', function () {

View File

@ -69,27 +69,24 @@
const reinit = function reinit() {
// Defaults.
const _antizapret = {
/* Don't use directly, please.
Encoded to counter abuse. */
host: '\x70\x72\x6f\x78\x79\x2e\x61\x6e\x74\x69\x7a\x61\x70\x72\x65\x74\x2e\x70\x72\x6f\x73\x74\x6f\x76\x70\x6e\x2e\x6f\x72\x67',
};
privates._strToHostObj = {
[_antizapret.host]: _antizapret,
};
privates._strToHostObj = [
/* Please, don't use proxies directly (without PAC-script). */
'n.thenewone.lol',
's.thenewone.lol',
// antizapret.prostovpn.org:
'proxy.antizapret.prostovpn.org',
'proxy-ssl.antizapret.prostovpn.org',
'proxy-nossl.antizapret.prostovpn.org',
'proxy-fbtw-ssl.antizapret.prostovpn.org',
].reduce((acc, hostname) => Object.assign(acc, { [hostname]: { host: hostname }}), {
// Defaults:
localhost: { host: 'localhost' },
});
privates._ipToHostObj = {};
for( const ip of [
// IPs of Antizapret.
'195.123.209.38',
'137.74.171.91',
'51.15.39.201',
'2001:bc8:4700:2300::1:d07',
'2a02:27ac::10',
] ) {
privates._ipToHostObj[ip] = _antizapret;
}
privates._ipToHostObj = {
'127.0.0.1': { host: 'localhost' },
'0.0.0.0': { host: 'localhost' },
};
// Persisted.
const ipToHost = _state(ip2host);
@ -115,7 +112,7 @@
const getIpsFor = function getIpsFor(host, cb = mandatory()) {
if (host.trim() === 'localhost') {
return cb(null, ['127.0.0.1', '::1']);
return cb(null, ['127.0.0.1', '0.0.0.0', '::1']);
}
const types = [1, 28];
const promises = types.map(
@ -237,12 +234,11 @@
getIpsFor(hostStr, (err, ips, ...warns) => {
console.log('Got IPs + err?:', ips, err);
if (!err) {
resolveIps(ips);
} else {
if (err) {
reject([err, null, ...warns]);
return;
}
resolveIps(ips);
});
}).then(
@ -264,7 +260,9 @@
_updateAllAsync(cb = mandatory()) {
const hostArr = Object.keys(privates._strToHostObj);
const hostArr = Object.keys(privates._strToHostObj)
.filter((hostStr) => hostStr !== 'localhost');
console.log('Update all:', hostArr);
const promises = hostArr.map(
@ -277,29 +275,18 @@
);
Promise.all( promises ).then( (cbsRes) => {
const errors = cbsRes.map( ([err]) => err ).filter( (err) => err );
let newError;
const ifAllErrors = cbsRes.length === errors.length;
if (errors.length) {
if (ifAllErrors) {
newError = errors.shift();
} else {
newError = errors;
}
newError = clarify(
newError,
let ipErrors = cbsRes.map( ([err]) => err ).filter( (err) => err );
let warns = [];
if (ipErrors.length) {
warns = [clarify(
ipErrors,
'Не удалось получить один или несколько IP адресов для' +
' прокси-серверов. Иконка для уведомления об обходе' +
' блокировок может не отображаться.'
);
if (ifAllErrors) {
return cb(newError);
}
}
cb(null, null, newError);
)];
} else {}
cb(null, null, ...warns);
});
},
_replaceAllAsync(hostArr = mandatory(), cb) {

View File

@ -2,7 +2,137 @@
{
chrome.webNavigation.onErrorOccurred.addListener((details) => {
const timeouted = window.utils.timeouted;
const isProxied = (requestDetails) => false;
const isProxySideError = (details) =>
/* About !main_frame: Main frame websocket errors are followed by webnavigation errors
which chrome-internals code resets the state of the popup.
*/
details.error === 'net::ERR_TUNNEL_CONNECTION_FAILED' && details.type !== 'main_frame' && isProxied(details) ||
details.error === 'NS_ERROR_CONNECTION_REFUSED' && Boolean(details.proxyInfo);
const urlToA = (url) => new URL(url).host.link(
encodeURIComponent(url),
);
const isProxyErrorHandledAsync = async (details) => {
if (!isProxySideError(details)) {
return;
}
let fromPageHref = '';
let toUrlHref = '';
let fromPageHtml = '';
let youMayReportHtml = '';
const initiator = details.initiator !== 'null' && details.initiator;
try {
if (initiator) {
fromPageHref = new URL(initiator).href; // Sanitize: only urls, not other stuff.
fromPageHtml = ` со страницы ${urlToA(fromPageHref)}`;
}
toUrlHref = new URL(details.url).href;
youMayReportHtml = ` Вы можете <b>${'сообщить об ошибке'.link(
encodeURIComponent(
'/pages/report-proxy-error/index.html?' +
new URLSearchParams({
fromPageHref,
requestFailedTo: toUrlHref,
}),
),
)}</b> администратору прокси.`;
} catch(e) {
/* For malformed urls. */
console.log('Error handling malformed URLs:', details);
const msg = `Error handling malformed URLs: ${JSON.stringify(details, null, 2)}`;
throw new TypeError(msg);
}
// Service workers have tabId = -1, get active tubId for them.
const tabId = details.tabId < 0
? await new Promise((resolve) => chrome.tabs.query(
{ active: true },
([tab]) => resolve(tab.id)),
)
: details.tabId;
const [oldPopup, oldText, oldColor] = await new Promise((resolve) =>
chrome.browserAction.getPopup({ tabId }, (oldPopup) =>
chrome.browserAction.getBadgeText({ tabId }, (oldText) =>
chrome.browserAction.getBadgeBackgroundColor({ tabId }, (oldColor) => resolve([
oldPopup,
oldText,
oldColor,
])),
),
)
);
const popupPrefix = chrome.runtime.getURL(`/pages/options/index.html?status=<span style="color: red">🔥 Прокси-сервер отказался обслуживать запрос к%20`);
if (decodeURIComponent(oldPopup).startsWith(popupPrefix)) {
return true;
}
const popup = `${popupPrefix}${urlToA(details.url)}${fromPageHtml}</span>. Это могло быть намеренно или по ошибке.${youMayReportHtml}#tab=exceptions`;
chrome.browserAction.setPopup({
tabId,
popup,
});
chrome.browserAction.setBadgeBackgroundColor({
tabId,
color: 'red',
});
chrome.browserAction.setBadgeText({
tabId,
text: '❗',
});
let limit = 5;
let ifOnTurn = true;
let ifError = false;
const flip = () => {
if (!ifOnTurn && !--limit || ifError) {
clearInterval(timer);
return;
}
chrome.browserAction.setBadgeText({
tabId,
text: ifOnTurn ? '❗' : '',
}, () => {
ifError = chrome.runtime.lastError;
});
ifOnTurn = !ifOnTurn;
};
flip();
const timer = setInterval(flip, 500);
const restoringHandler = timeouted((eventDetails) => {
if(eventDetails && tabId !== ((eventDetails.currentTab || eventDetails).id || eventDetails.tabId)) {
return;
}
clearInterval(timer);
chrome.browserAction.setPopup({ tabId, popup: oldPopup});
chrome.browserAction.setBadgeBackgroundColor({ tabId, color: oldColor});
chrome.browserAction.setBadgeText({ tabId, text: oldText});
chrome.runtime.onMessage.removeListener(restoringHandler);
chrome.tabs.onRemoved.removeListener(restoringHandler);
chrome.tabs.onReplaced.removeListener(restoringHandler);
chrome.webNavigation.onBeforeNavigate.removeListener(restoringHandler);
});
chrome.runtime.onMessage.addListener(restoringHandler);
chrome.tabs.onRemoved.addListener(restoringHandler);
chrome.tabs.onReplaced.addListener(restoringHandler); // When does it happen?
chrome.webNavigation.onBeforeNavigate.addListener(restoringHandler);
return true;
};
chrome.webNavigation.onErrorOccurred.addListener(timeouted(async (details) => {
const tabId = details.tabId;
if ( !(details.frameId === 0 && tabId >= 0) ||
@ -12,13 +142,16 @@
].includes(details.error) ) {
return;
}
if (await isProxyErrorHandledAsync(details)) {
return;
}
chrome.browserAction.setPopup({
tabId,
popup: './pages/options/index.html#tab=exceptions&status=Правый клик по иконке — меню инструментов!',
popup: './pages/options/index.html?status=Правый клик по иконке — меню инструментов!#tab=exceptions',
});
window.chrome.browserAction.setBadgeBackgroundColor({
chrome.browserAction.setBadgeBackgroundColor({
tabId,
color: '#4285f4',
});
@ -27,6 +160,10 @@
text: '●●●',
});
});
}));
chrome.webRequest.onErrorOccurred.addListener(
timeouted(isProxyErrorHandledAsync),
{urls: ['<all_urls>']},
);
}

View File

@ -9,8 +9,6 @@
to "loading".
So if you set a title earlier it may be cleared by browser.
It pertains not only to page refesh but to newly opened pages too.
Also on loosing title see:
https://github.com/ilyaigpetrov/repository-for-chrome-bugs/blob/master/browserAction-title-lost-after-setting/background.js
Crazy parallel Chrome.
**/
@ -43,7 +41,7 @@
const setRedBadge = (opts) => {
window.chrome.browserAction.setBadgeBackgroundColor({
chrome.browserAction.setBadgeBackgroundColor({
color: '#db4b2f',
});
chrome.browserAction.setBadgeText(opts);
@ -59,7 +57,7 @@
if (err) {
// E.g., no tab with such id happens.
// Because requestDetails may be stale.
console.log('Notifier error ignored:', err);
console.log('Notifier error ignored (this is normal, it happens):', err);
return cb();
}
const ifTitleSetAlready = /\n/.test(title);
@ -142,6 +140,23 @@
if (!host) {
return;
}
{
/*
If we fetch a resource from a proxy address it is almost never proxied and
shouldn't be shown.
Think about localhost as a proxy and a user working with a web site on localhost.
*/
/*
Host is constructed from hostname and port. Hostname never contains port,
it is an ip or a domain name. See hostname and host
in `new URL('https://localhost:8080')`.
*/
const hostnameFromUrl = new URL(requestDetails.url).hostname;
const hostnameFromProxy = new URL(`https://${host}`).hostname;
if (hostnameFromUrl === requestDetails.ip || hostnameFromUrl === hostnameFromProxy) {
return;
}
}
const ifMainFrame = requestDetails.type === 'main_frame';

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Сообщить об ошибке прокси-сервера</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
font-size: 1.3em;
}
</style>
</head>
<body>
<h1>Сообщить об ошибке прокси-сервера</h1>
Перешлите администратору вашего прокси следующее:
<fieldset>
<pre id="errorInfo"></pre>
</fieldset>
Вот известные нам электронные адреса для популярных прокси-серверов (кликните по email для открытия шаблона письма):
<ol>
<li>
Только если вы используете <a
href="https://antizapret.prostovpn.org">Антизапрет</a>:
<a
href="mailto:antizapret@prostovpn.org">antizapret@prostovpn.org</a>.
</li>
</ol>
<script src="./index.js"></script>
<script src="../lib/keep-links-clickable.js"></script>
</body>
</html>

View File

@ -0,0 +1,39 @@
'use strict';
chrome.runtime.getBackgroundPage( (bgWindow) =>
bgWindow.apis.errorHandlers.installListenersOn(
window, 'PRERR', () => {
const params = new URLSearchParams(location.search.substr(1));
const requestFailedTo = params.get('requestFailedTo');
const fromPageHref = params.get('fromPageHref') || requestFailedTo;
const acr = bgWindow.apis.antiCensorRu;
const pacKey = acr.getCurrentPacProviderKey();
const pacModTime = acr.getLastModifiedForKey(pacKey);
const errorReport = `
Your proxy blocked the following request:
* Request was from page: ${fromPageHref}
* To address: ${requestFailedTo}
* Used PAC-script: ${pacKey}
* Its Last-Modified HTTP-header: ${pacModTime}
I think it's a mistake! Could you, please, take action to fix it.
Thank you!
Ваш прокси-сервер заблокировал следующий запрос:
* Запрос был со страницы: ${fromPageHref}
* Адрес запроса: ${requestFailedTo}
* Мой PAC-скрипт: ${pacKey}
* Его HTTP-заголовок Last-Modified: ${pacModTime}
Я думаю, это произошло по ошибке! Пожалуйста, примите действия для её исправления.
Спасибо!
`.trim();
errorInfo.innerText = errorReport;
document.querySelectorAll('a[href^="mailto:"]').forEach((a) => {
a.href = `${a.href}?subject=${encodeURIComponent(new URL(requestFailedTo).hostname)} TUNNEL_CONNECTION_FAILED&body=${encodeURIComponent(errorReport)}`;
});
},
),
);

View File

@ -1,31 +1,30 @@
'use strict';
const pacUrls = [
// GitHub.io (anticensority), cached:
'https://anticensority.github.io/generated-pac-scripts/anticensority.pac',
// GitHub repo (anticensority), cached:
'https://raw.githubusercontent.com/anticensority/generated-pac-scripts/master/anticensority.pac',
];
const commonContext = {
version: '1.5',
version: '1.66',
anticensorityPacUrls: [
// First official, shortened:
'https://rebrand.ly/ac-chrome-anticensority-pac',
// Second official, Cloud Flare with caching:
'https://anticensority.tk/generated-pac-scripts/anticensority.pac',
// GitHub.io (anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x67\x69\x74\x68\x75\x62\x2e\x69\x6f\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
// GitHub repo (anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x72\x61\x77\x2e\x67\x69\x74\x68\x75\x62\x75\x73\x65\x72\x63\x6f\x6e\x74\x65\x6e\x74\x2e\x63\x6f\x6d\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2f\x67\x65\x6e\x65\x72\x61\x74\x65\x64\x2d\x70\x61\x63\x2d\x73\x63\x72\x69\x70\x74\x73\x2f\x6d\x61\x73\x74\x65\x72\x2f\x61\x6e\x74\x69\x63\x65\x6e\x73\x6f\x72\x69\x74\x79\x2e\x70\x61\x63',
// Old, deprecated:
'https://anticensorship-russia.tk/generated-pac-scripts/anticensority.pac',
// Google Drive (0.17, anticensority):
'\x68\x74\x74\x70\x73\x3a\x2f\x2f\x64\x72\x69\x76\x65\x2e\x67\x6f\x6f\x67\x6c\x65\x2e\x63\x6f\x6d\x2f\x75\x63\x3f\x65\x78\x70\x6f\x72\x74\x3d\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x26\x69\x64\x3d\x30\x42\x32\x6d\x68\x42\x67\x46\x6e\x66\x34\x70\x45\x4c\x56\x6c\x47\x4e\x54\x42\x45\x4d\x58\x4e\x6d\x52\x58\x63',
]
...pacUrls,
],
};
exports.contexts = {};
const extra_permissions = ', "webRequest", "webRequestBlocking", "webNavigation"';
exports.contexts.full = Object.assign({}, commonContext, {
versionSuffix: '',
nameSuffixEn: '',
nameSuffixRu: '',
extra_permissions: ', "webRequest", "webNavigation"',
extra_permissions,
persistent: '',
scripts_0x: '',
scripts_2x: ', "20-ip-to-host-api.js"',
scripts_8x: ', "80-error-menu.js", "83-last-errors.js", "85-block-informer.js"',
});
@ -36,18 +35,34 @@ exports.contexts.mini = Object.assign({}, commonContext, {
nameSuffixRu: ' МИНИ',
extra_permissions: '',
persistent: '"persistent": false,',
scripts_0x: '',
scripts_2x: ', "20-for-mini-only.js"',
scripts_8x: '',
});
exports.contexts.beta = Object.assign({}, commonContext, {
anticensorityPacUrls: ['https://rebrand.ly/ac-beta-pac'],
version: '1.5',
exports.contexts.firefox = Object.assign({}, commonContext, {
versionSuffix: '',
nameSuffixEn: ' FOR TESTING',
nameSuffixRu: ' ДЛЯ ТЕСТОВ',
extra_permissions: ', "webRequest", "webNavigation"',
nameSuffixEn: '',
nameSuffixRu: '',
extra_permissions,
persistent: '',
scripts_0x: ', "01-chrome-proxy-settings.js"',
scripts_2x: ', "20-ip-to-host-api.js"',
scripts_8x: ', "80-error-menu.js", "83-last-errors.js", "85-block-informer.js"',
});
exports.contexts.beta = Object.assign({}, commonContext, {
anticensorityPacUrls: [
'https://raw.githubusercontent.com/anticensority/for-testing/master/anticensority.pac',
'https://anticensority.github.io/for-testing/anticensority.pac',
],
version: '1.14',
versionSuffix: '',
nameSuffixEn: ' FOR TESTING',
nameSuffixRu: ' ДЛЯ ТЕСТОВ',
extra_permissions,
persistent: '',
scripts_0x: '',
scripts_2x: ', "20-ip-to-host-api.js"',
scripts_8x: ', "80-error-menu.js", "83-last-errors.js", "85-block-informer.js"',
});

File diff suppressed because it is too large Load Diff

17
package.json Executable file → Normal file
View File

@ -2,17 +2,16 @@
"name": "subjective-good-is-evil",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"generate": "cd pac-generator && npm start",
"prestart": "npm run generate",
"start": "npm run bench",
"bench": "cd ./pac-performance-analyses/benchmark && dnx run ../../pac-generator/generated-PACs",
"test": "rm -r pac-generator/generated-PACs"
"postinstall": "opencollective postinstall"
},
"author": "ilyaigpetrov",
"author": "anticensority+owners@googlegroups.com",
"license": "ISC",
"devDependencies": {
"http-server": "^0.8.5"
"dependencies": {
"opencollective": "^1.0.3"
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/anticensority"
}
}