1
0
mirror of https://github.com/kkapsner/CanvasBlocker synced 2024-05-29 09:28:06 +02:00

Compare commits

...

259 Commits
1.1 ... master

Author SHA1 Message Date
kkapsner
4f366ed86c
New translations 2024-04-17 00:35:54 +02:00
kkapsner
00e60074c3 Don't throw target.apply is not a function
For #705
2024-04-17 00:34:19 +02:00
kkapsner
3eedc7b7dc Only check for prototype loops when there is a prototype
For #705
2024-04-17 00:07:16 +02:00
kkapsner
bebcec2139 Version 1.11 2024-04-16 14:53:11 +02:00
kkapsner
5181a55071 change "Site specific" to "Site-specific" 2024-04-10 16:06:56 +02:00
kkapsner
a8e192fa9b change "non persistent" to "nonpersistent"
For #696
2024-04-09 14:04:51 +02:00
kkapsner
0f3141ee12
New translations
For #696
2024-04-09 14:03:06 +02:00
kkapsner
e9ce4668fe
New translations 2024-04-09 14:01:35 +02:00
kkapsner
acce01bfeb Mark default value in drop downs settings
For #696
2024-04-08 00:15:55 +02:00
kkapsner
d159769997 Added :changed tag
For #696
2024-04-08 00:12:46 +02:00
kkapsner
56401048d1 Added tag search 2024-04-08 00:09:37 +02:00
kkapsner
54c625cd26 Fix function tampering detection via prototype
For #619 and #685
2024-04-08 00:05:50 +02:00
kkapsner
7bb3f00b45 Update releaseNotes.txt 2024-04-08 00:04:53 +02:00
kkapsner
b8c6115603 Not using proxy for toString broke google
For #698, #699, #700, #701
2024-04-07 23:59:49 +02:00
kkapsner
dacc578e12 Alpha versions must not break with patches 2024-04-07 02:36:20 +02:00
kkapsner
825fa42141 Fix isPointInPath and isPointInStroke
Fixes #696
2024-04-07 01:53:01 +02:00
kkapsner
40a8012ab0 Version 1.10.1 2024-04-04 23:30:20 +02:00
kkapsner
ec95cbe11b Bump min version to 100
to avoid warnings in the upload process
2024-03-30 17:27:30 +01:00
kkapsner
36b54f3ab5 Update navigator test to include storage.quota 2024-03-30 13:58:09 +01:00
kkapsner
87790c9731 Remove facebook.com from the convenience preset
Fixes #563
2024-03-30 13:54:47 +01:00
kkapsner
200f6b31f3 Do not use proxy for Function.prototype.toString
Fixes #685
2024-03-29 16:37:07 +01:00
kkapsner
1d8bf95926 Added protection for navigator.storage.estimate()
Fixes #681
2024-03-28 16:53:01 +01:00
kkapsner
c6cf48c489 Display version
Fixes #687
2024-03-28 14:43:53 +01:00
kkapsner
9a3745b366 Whitelist also data URL blocking
Fixes #665
2024-03-28 14:40:08 +01:00
kkapsner
a18e3ba37d Disable cache when reloading in the browser action 2024-03-28 14:26:20 +01:00
kkapsner
645d0ac550 dictionary update 2024-03-28 14:23:31 +01:00
kkapsner
809c1270c5
New translations 2024-03-28 14:21:13 +01:00
kkapsner
a99a0615d0 Update dev dependencies 2024-03-28 14:20:01 +01:00
kkapsner
bc13a5e2a2 Fix typos 2024-03-28 14:18:37 +01:00
kkapsner
8176ac83dc
New translations
* New Spanish translations
* New German translations
* New Portuguese translations
* New Russian translations
* New Portuguese (Brazilian) translations
2024-03-28 14:07:25 +01:00
kkapsner
4a2079bf47 Add alpha version to updates.json during build 2024-02-17 00:07:11 +01:00
kkapsner
7229133c8d Update build tool for manifest version v3 2024-02-17 00:02:10 +01:00
kkapsner
8bdedfcb3d Update package-lock.json 2024-02-16 23:48:34 +01:00
kkapsner
ae40caed09 Update package-lock.json 2023-07-19 01:22:11 +02:00
kkapsner
053ae6725e remove crowdin.yml from build 2023-05-30 19:04:40 +02:00
kkapsner
2a6c564ed8 Remove usage of deprecated browser.extension.getURL 2023-05-30 19:04:02 +02:00
kkapsner
8a84dd09f3
New translations
Lithuanian
2023-05-30 13:50:52 +02:00
kkapsner
df039b0f3c Do not use UTC for alpha version 2023-05-30 13:48:25 +02:00
kkapsner
fc5cce23ea Increase bottom padding of options page 2023-05-30 13:42:30 +02:00
kkapsner
e9f5f710e6 Replace window.open with browser.tabs.create
Fixes #661
2023-05-30 00:20:54 +02:00
kkapsner
5df98e0cf5 Settings export page did not show whole content in Firefox for Android 2023-05-30 00:11:43 +02:00
kkapsner
6ea89b6318 Improve isMobile
Fixes #658
2023-05-29 21:41:42 +02:00
kkapsner
02dfa8bd1b browser.windows.onRemoved not available on Fenix
Fix #654
2023-05-29 21:39:02 +02:00
kkapsner
8dcfac442f Added eBay and facebook.com to the convenience preset
Fixes #563
2023-05-29 14:48:56 +02:00
kkapsner
27d8d61da6 Update release notes
For #656
2023-05-29 14:44:36 +02:00
kkapsner
fb1311a842 Added showPresetsOnInstallation
Fixes #656
2023-05-29 14:05:03 +02:00
kkapsner
114b109340 Enable multiple alpha versions per day 2023-04-19 14:48:47 +02:00
kkapsner
4ce2f98b10 Fix alpha version 2023-04-19 14:48:23 +02:00
kkapsner
2c5b00a55d Always protect about:blank
Fixes #652
2023-04-19 14:34:37 +02:00
kkapsner
d6916b013e Version 1.10 2023-04-19 14:24:41 +02:00
kkapsner
3b92824d0f Update web-ext to 7.6.1 2023-04-15 20:00:07 +02:00
kkapsner
d3558f0bd7 Update release notes
was missing change for screen API
2023-04-15 16:17:59 +02:00
kkapsner
d55921ba92 Added known issue to release notes 2023-04-15 16:07:34 +02:00
kkapsner
1ca13299ec New alpha version 2023-04-15 16:07:15 +02:00
kkapsner
53ce86a21f Update release notes 2023-04-07 17:42:16 +02:00
kkapsner
269574ae17 Respect RFP in offscreenToBlobCallback
Fixes #644
2023-04-07 17:35:57 +02:00
kkapsner
3b08fdaf9b Improve github issue template 2023-04-07 10:01:29 +02:00
kkapsner
e0e6926a74 Use correct tab in browserAction (private browsing)
Fixes #649
2023-04-07 09:22:03 +02:00
kkapsner
2ac1ec277d Fix typos with firefoxVersionRV 2023-03-25 11:36:01 +01:00
kkapsner
8e463a6164 Update web-ext to 7.6.0 2023-03-22 13:04:33 +01:00
kkapsner
2cefed00a7 Fix alpha building tool 2023-03-22 13:04:09 +01:00
kkapsner
7cd4b2e9fa Updated browser presets 2023-03-18 14:45:32 +01:00
kkapsner
8d3f489d11 Added {real Firefox version - rv} to Firefox navigator preset
Fixes #641
2023-03-18 14:44:44 +01:00
kkapsner
34bc1730a1 Added dhl.de to the convenience preset
Fixes #532
2023-03-14 20:08:14 +01:00
kkapsner
f900c25900
New translations
* New Italian translations
* New Korean translations
2023-03-14 16:50:19 +01:00
kkapsner
6b172a0a4c Update manifest.json for new manifest version 2023-03-14 16:49:37 +01:00
kkapsner
46eb608f4e Update package-lock.json 2023-03-14 16:43:20 +01:00
kkapsner
b46341de90 Update web-ext 2022-09-04 15:19:03 +02:00
kkapsner
91b7dcbb11 Update readme regarding built-in fingerprinting protection
Fixes #628
2022-09-04 15:15:50 +02:00
kkapsner
582a962d8d
New translations 2022-08-28 17:47:48 +02:00
kkapsner
d9c14d7eed Use public bounce for data-URL test
Fixes #615
2022-05-04 13:30:47 +02:00
kkapsner
4bd0c0c96c Added support for wildcards (*) in domains
Fixes #613
2022-04-26 17:08:28 +02:00
kkapsner
cfb09075eb Fetch errors in URL regular expressions creation #2
Fixes #602
2022-04-24 20:50:06 +02:00
kkapsner
4443d0a117 Improve issue template 2022-04-24 20:47:58 +02:00
kkapsner
bb71b10c58
Fixed typo in other languages 2022-04-22 10:12:17 +02:00
kkapsner
4d4cda678c Fix typo 2022-04-22 10:08:03 +02:00
kkapsner
6c6012edf4
Update descriptions in all languages
For #591 and #607
2022-04-21 21:24:00 +02:00
kkapsner
05f8f936e9 Update description of the rngs
Fixes #591
2022-04-21 21:11:44 +02:00
kkapsner
1a199a5049 Updated description of webGL vendor and renderer
Fixes #607
2022-04-21 17:18:27 +02:00
kkapsner
e5cba569ba Fix npm audit 2022-04-15 13:54:27 +02:00
kkapsner
fd09e3d5cf Use inner of top window for all outer computations
For #598
2022-04-04 18:10:16 +02:00
kkapsner
6aab7f68ea
New translations
* Czech
* Chinese Simplified
* Portuguese, Brazilian
* French
* Spanish
2022-03-30 16:48:33 +02:00
kkapsner
a92373f412 Update web-ext 2022-03-30 16:46:28 +02:00
kkapsner
b4cb52df15 Fix eslint warning 2022-03-17 23:05:46 +01:00
kkapsner
d100932236 Allow clicks in url change input
Fixes #600
2022-03-17 22:44:52 +01:00
CommanderRoot
bfa355b58d
Replace deprecated String.prototype.substr() 2022-02-21 19:46:02 +01:00
kkapsner
dc593daba8 Update eslint and web-ext 2022-02-20 23:31:23 +01:00
kkapsner
029933964f Version 1.9 2022-02-18 19:45:27 +01:00
kkapsner
ffd659c7bb Update release notes 2022-02-17 17:39:35 +01:00
kkapsner
f788cd4263
New translations 2022-02-17 17:19:05 +01:00
kkapsner
1bd87e6953 Added <option1|option2|...> syntax to webGL
Fixes #493
2022-02-15 19:53:58 +01:00
kkapsner
fb231a070b Added {random vendor} and {random renderer}
For #493
2022-02-14 17:37:54 +01:00
kkapsner
740b360485 Linting 2022-02-13 14:57:36 +01:00
kkapsner
3621fef625 Fix slight code problems in svg-test 2022-02-13 14:54:48 +01:00
kkapsner
3d603b84d4 Added notice when dom.webAudio.enabled is set to false
Fixes #592
2022-01-30 17:50:59 +01:00
kkapsner
d4fc7027eb Fetch errors in URL regular expressions creation
Fixes #581
2022-01-30 13:11:44 +01:00
kkapsner
4c364a9a72
New translations 2022-01-30 11:16:54 +01:00
kkapsner
863140c1ca Added anchors to FAQ 2022-01-30 11:00:00 +01:00
kkapsner
640bd36b86 Added SVG protection
Fixes #589 and fixes #590
2022-01-30 10:59:41 +01:00
kkapsner
734e76180f Added test for SVG
For #589 and #590
2022-01-30 10:05:52 +01:00
kkapsner
78183f9efc Version 1.8 2021-11-07 16:20:39 +01:00
kkapsner
f043acf41c Release preparation 2021-11-07 11:09:53 +01:00
kkapsner
892e4d2c34
New translations 2021-11-01 13:57:01 +01:00
kkapsner
d97864436d update release notes 2021-11-01 13:54:59 +01:00
kkapsner
7f154c6cc6 Do not use browser.extension.getURL 2021-11-01 13:18:38 +01:00
kkapsner
6f5cfc1080
New Italian translations 2021-09-09 17:42:29 +02:00
kkapsner
cca81c4006 Do not add CSP headers to 304 requests
Fixes #577
2021-09-09 17:40:18 +02:00
kkapsner
2f6ca07bba Added 304 test
For #577
2021-09-08 23:09:08 +02:00
kkapsner
8e4a881288 Close browserAction when a new page is opened
Fixes #576
2021-08-17 19:01:44 +02:00
kkapsner
709093fa4d Update web-ext 2021-07-04 09:28:57 +02:00
kkapsner
b9d5eb3d27 Version 1.7 2021-06-21 23:28:36 +02:00
kkapsner
e8ee1f8e9c Verion 1.6.1
Fixes #564
2021-06-21 22:01:09 +02:00
kkapsner
4ac02003de wrapped original funtion may gets destroyed before usage
For #564
2021-06-21 20:41:33 +02:00
kkapsner
cf0243d487 Version 1.7 2021-06-20 14:42:13 +02:00
spodermenpls
34f9dfa4fd
Status Icon revision
For #535
2021-06-14 22:25:22 +02:00
kkapsner
bce494e744 Improve whitelist button
For #535
2021-06-13 21:08:28 +02:00
kkapsner
87646a152a New alpha version 2021-06-12 01:04:47 +02:00
kkapsner
de14490574
New translations 2021-06-12 01:03:47 +02:00
kkapsner
13203a905d arrayFake did not correctly compute if values were faked
Fixes #531
2021-06-12 00:58:37 +02:00
kkapsner
277bef1227 Clean up white spaces 2021-06-12 00:50:05 +02:00
kkapsner
015350c385 Add reload button to browser action
For #535
2021-06-12 00:49:10 +02:00
kkapsner
cdfe72fada Use dedicated icons for the whitelist toggle
For #535
2021-06-12 00:04:17 +02:00
kkapsner
57bf81ec3a Cleanup icons 2021-06-12 00:03:22 +02:00
kkapsner
43ea01c178 Add whitelist type selection
Fixes #538
2021-06-08 23:42:19 +02:00
kkapsner
3722263a6f Documentation 2021-06-08 15:40:15 +02:00
kkapsner
020a9c5b9a Whitelisted block mode should be "allowEverything" 2021-06-08 15:31:37 +02:00
kkapsner
698fc02e66
New French translations 2021-06-08 13:25:58 +02:00
kkapsner
7ae6e14d0d
New translations 2021-06-07 21:33:31 +02:00
kkapsner
539ddf5e46 Update web-ext to 6.1.0 2021-06-07 21:30:26 +02:00
kkapsner
70a941f5aa Added FAQ for url specific settings
Fixes #550
2021-06-07 21:04:59 +02:00
kkapsner
51e76bafce New alpha version 2021-06-06 15:01:32 +02:00
kkapsner
8dddff85cc Cleanup 2021-06-06 14:43:46 +02:00
kkapsner
0d581403c1 toBlob is not a constructor 2021-05-26 08:19:43 +02:00
kkapsner
0930928df3 detectionTest: check function code also in an iFrame 2021-05-26 08:19:43 +02:00
kkapsner
a7d02efd09 Fix toString for proxies 2021-05-26 08:19:43 +02:00
kkapsner
aa3f9d878d detectionTest: made addTest asynchronous 2021-05-26 08:19:43 +02:00
kkapsner
211d6710f6 First proxy attempt 2021-05-26 08:19:43 +02:00
kkapsner
42b19a4ba5 Added status button in browser action to see and set the whitelist status
Fixes #535
2021-05-25 16:44:20 +02:00
kkapsner
16bef43945 Update npm modules for dev 2021-05-08 21:22:23 +02:00
kkapsner
b614b84b5f Set random supply if settings were preloaded
Fixes #544
2021-05-04 22:52:37 +02:00
kkapsner
bde9d3c012 Added FAQ for PayPal problem
Fixes #532
2021-03-12 13:43:51 +01:00
kkapsner
32af464c05 Improved whitelist inspection
Fixes #501
2021-03-06 22:52:52 +01:00
kkapsner
1e1f343f28 New alpha version 2021-03-06 13:56:11 +01:00
kkapsner
7cd4ecec44
New translations 2021-03-06 11:18:59 +01:00
kkapsner
4f5b9b5f78 Linting 2021-03-06 11:17:04 +01:00
kkapsner
be55cbf983 Added paypal.com to the convenience preset
For #532
2021-03-06 11:16:20 +01:00
kkapsner
872e633025 Convenience preset did not work properly 2021-03-06 11:10:18 +01:00
kkapsner
ee87773ce2 Limit periodical rnd clearing
Periodical persistent rnd clearing does not clear in active tabs.

Fixes #518
2021-02-21 11:49:29 +01:00
kkapsner
28dd7f6819
New translations 2021-01-26 21:56:37 +01:00
kkapsner
a5558b4144 Add button to reload extension if update pending
For #522
2021-01-26 21:45:15 +01:00
kkapsner
8e5986817e Update improvements
For #522
2021-01-26 13:47:11 +01:00
kkapsner
e48710eee9 Fix message canvasBlocker-unload
For #522
2021-01-26 13:34:51 +01:00
kkapsner
1b04da40c2 Update web-ext 2021-01-18 21:50:14 +01:00
kkapsner
afd426da58 Version 1.6 2021-01-18 21:42:12 +01:00
kkapsner
0d160143c1 Update release notes 2021-01-18 21:11:14 +01:00
kkapsner
b94de2b641
New translations
* new French translations
* new Italian translations
2021-01-18 20:37:47 +01:00
kkapsner
945c2716c9 Improved input faking performance further
fixes #517
2021-01-13 20:06:03 +01:00
kkapsner
1f1d7052a1 Fix bug in webGl parameter faking
Fixes #508
2021-01-03 22:23:46 +01:00
kkapsner
e2c5dfc06e added {disabled} to UNMASKED_VENDOR_WEBGL and UNMASKED_RENDERER_WEBGL
to disabled the WEBGL_debug_renderer_info extension

Fixes #508
2021-01-03 21:11:17 +01:00
kkapsner
b4a744660b Improved performance for protected canvas part "input"
Fixes #517
2021-01-03 17:36:40 +01:00
kkapsner
fcbc622cef Revert iframe protection upon window unload
Fixes #519
2021-01-03 17:32:57 +01:00
kkapsner
f4d09e43ac added {empty}, {false} and {undefined} to webGL preference parameters
(i.e. VENDOR, RENDERER, UNMASKED_VENDOR_WEBGL and
UNMASKED_RENDERER_WEBGL)

For #508
2021-01-02 11:05:52 +01:00
kkapsner
ae526e4710
Polish translation 2020-12-12 11:08:40 +01:00
kkapsner
822218a00c Update packages 2020-12-12 11:04:05 +01:00
kkapsner
4e6f76ab75 New translations messages.json (Polish) 2020-11-25 15:39:33 +01:00
kkapsner
543365cd64 New translations messages.json (Polish) 2020-11-25 15:29:45 +01:00
kkapsner
1125d6f1a8 Minimal styling on test pages
For #106
2020-11-21 13:58:32 +01:00
kkapsner
7178b409c3 Version 1.5 2020-11-21 13:28:40 +01:00
kkapsner
b7e1b50166 New translations messages.json (Polish) 2020-11-14 00:28:31 +01:00
kkapsner
184b6bb47c New translations messages.json (Polish) 2020-11-14 00:20:04 +01:00
kkapsner
586bc97d38 New translations messages.json (Polish) 2020-11-12 23:58:58 +01:00
kkapsner
8f13588e61 New translations messages.json (Polish) 2020-11-12 23:45:23 +01:00
kkapsner
8c852e96c9 New translations messages.json (Polish) 2020-11-10 19:19:55 +01:00
kkapsner
23f2bf8b23 New translations messages.json (Polish) 2020-11-10 18:50:30 +01:00
kkapsner
83394afc90 Update release notes 2020-11-09 08:33:04 +01:00
kkapsner
0f61318c27 Style index pages 2020-11-09 08:27:45 +01:00
kkapsner
716e6aa6a9
New Crowdin updates (#492)
* New translations messages.json (Chinese Traditional)

* New translations messages.json (German)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)

* New translations messages.json (Italian)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese)
2020-11-02 13:54:43 +01:00
kkapsner
701eb979ed Updated DOMRect protection 2020-11-02 13:49:42 +01:00
kkapsner
d5417cf807 Improved exportFunctionWithName
To reduce the need of double exports.
2020-11-02 13:11:50 +01:00
kkapsner
c16068ca85 domRectTest: update SVG tests 2020-11-02 13:07:40 +01:00
kkapsner
ef69e1dcb5 domRectTest: added IntersectionObserverEntry tests 2020-11-02 13:07:19 +01:00
kkapsner
902d31b643 Update npm packages 2020-11-02 12:01:18 +01:00
kkapsner
0a290b3521 Fix stuck Fenix
Fixes #503
2020-11-02 11:54:43 +01:00
kkapsner
e65ac94dda Added getImageData raw display test. 2020-10-26 14:17:34 +01:00
kkapsner
71c9baec0a domRectTest: added getBOXQuads test 2020-10-14 16:33:26 +02:00
kkapsner
ff98b9b9af domRectTest: added svg tests 2020-10-14 16:33:26 +02:00
kkapsner
3eea8fe7c4 domRectTest: hide detail data 2020-10-14 16:33:26 +02:00
litetex
3ab6366994
Options: Using by default json as prefered file type for loading settings (#500) 2020-10-14 16:29:36 +02:00
kkapsner
cd852a0c8b New translations messages.json (Portuguese) 2020-10-14 16:27:39 +02:00
kkapsner
864c2454e1 New translations messages.json (Portuguese) 2020-10-14 16:12:51 +02:00
kkapsner
8d7637e65b New translations messages.json (Italian) 2020-10-13 09:34:20 +02:00
kkapsner
393020630c New translations messages.json (Portuguese) 2020-10-12 12:23:21 +02:00
kkapsner
9779d14276 New translations messages.json (Portuguese) 2020-10-12 12:14:41 +02:00
kkapsner
5ab00a5584 New translations messages.json (Portuguese) 2020-10-12 12:05:12 +02:00
kkapsner
6a31bb3791 New translations messages.json (Portuguese) 2020-10-12 11:46:05 +02:00
kkapsner
beb3a969f3 New translations messages.json (Portuguese) 2020-10-12 11:33:45 +02:00
kkapsner
5964146e22 New translations messages.json (Portuguese) 2020-10-12 11:28:23 +02:00
kkapsner
679265a82f New translations messages.json (Portuguese) 2020-10-03 13:28:14 +02:00
kkapsner
d761411339 New translations messages.json (Portuguese) 2020-10-03 13:18:11 +02:00
kkapsner
1b3709bce5 New translations messages.json (German) 2020-07-27 12:53:50 +02:00
kkapsner
00e94f9ae4 Updated dev dependencies 2020-07-19 11:22:52 +02:00
kkapsner
c6bb9766f9 New translations messages.json (Chinese Traditional) 2020-07-15 16:42:09 +02:00
kkapsner
b9c9516b14
New trnaslations
* Chinese Traditional
* French
* Spanish
2020-07-07 13:17:13 +02:00
kkapsner
cb7a98d751 Updated devDependencies package.json
To remove vulnerabilities
2020-06-27 11:49:43 +02:00
kkapsner
21a950565f Fix alpha value in canvasAPI.js 2020-06-27 11:45:23 +02:00
kkapsner
d8b5ba0744 iframe test: added nested iframes test 2020-06-19 00:07:14 +02:00
kkapsner
ce1925d95f iframe test: better timing dependencies 2020-06-19 00:06:56 +02:00
kkapsner
2c1756ff07 Avoid useless URL specific setting in whitelist inspection
Fixes #483
2020-06-17 16:18:56 +02:00
kkapsner
c6e4027a7f
Added zh-TW
Fixes #479
2020-06-10 14:56:04 +02:00
kkapsner
5ac5c8cc66 Fix crowdin.yml 2020-06-10 14:46:48 +02:00
kkapsner
46bf7e04f4 Set exceptions to two letter code 2020-06-10 14:42:35 +02:00
kkapsner
10b2ef8e70 Version 1.4 2020-06-07 13:10:18 +02:00
kkapsner
ac2e074fdd Updated release notes 2020-06-07 11:32:29 +02:00
kkapsner
d9adcb4c3d
New Portuguese Brazilian translation 2020-06-03 20:03:01 +02:00
kkapsner
5b1c4bf6cc
New Crowdin translations
* New translations (Spanish)
* New translations (Italian)
* New translations (Polish)
* New translations (Russian)
* New translations (Chinese Simplified)
* New translations (Portuguese, Brazilian)
* New translations (Norwegian Bokmal)
2020-06-02 15:30:24 +02:00
kkapsner
8cf58ebe3b Updated updates.json 2020-06-01 14:42:38 +02:00
kkapsner
2e91f85d8f Added offscreen canvas protection
Fixes #467
2020-06-01 14:25:47 +02:00
kkapsner
2c141277e8 Set proper name for faked getContext 2020-06-01 14:03:32 +02:00
kkapsner
3e3dbf2698 Added noDraw parameter to webGL test. 2020-06-01 13:53:05 +02:00
kkapsner
0225f94890 Added FAQ for hidden settings 2020-05-31 13:59:28 +02:00
kkapsner
253d3f68b1 Added canvas cache to isPointInPath and isPointInStroke 2020-05-24 23:39:44 +02:00
kkapsner
da5a9f4509 webGL: added image hash tests 2020-05-21 00:11:25 +02:00
kkapsner
a79c4ec8c5 Added test for blob, offscreen canvas and offscreen canvas in workers 2020-05-19 10:48:08 +02:00
kkapsner
7c2a4edde0 Remove unnecessary CSS. 2020-05-19 10:10:38 +02:00
kkapsner
51b740632a Updated link to DOMRect test 2020-05-19 09:54:40 +02:00
kkapsner
9a7dd3c189 DOMRect test: added test without iframe 2020-05-18 13:22:33 +02:00
kkapsner
4fa91ef3ae Fix refresh bug in audio test 2020-05-01 01:11:21 +02:00
kkapsner
64adb49b81 Additional audio tests 2020-05-01 01:06:50 +02:00
kkapsner
49f3c166a2 Navigator test: added nested worker and worker from blob
Fixes #458
2020-04-15 00:25:24 +02:00
kkapsner
308d7c4005 Navigator test: added worker test
Fixes #458
2020-04-13 10:10:44 +02:00
kkapsner
87fa607d28
New Italian translations 2020-04-10 14:28:22 +02:00
kkapsner
aae0fa2f8b
New French translations 2020-04-05 15:04:41 +02:00
kkapsner
d834b7a14b Updated npm packages 2020-04-05 14:35:50 +02:00
TotalCaesar659
e2d18a143d
Update URL to HTTPS 2020-04-05 14:30:11 +02:00
kkapsner
8ee413a951
New translations 2020-03-22 16:36:14 +01:00
kkapsner
1fb7f7991b Added link to FAQ
For #106
2020-03-22 16:33:22 +01:00
kkapsner
7cfc43194a Text corrections/improvements. 2020-03-22 14:25:15 +01:00
kkapsner
e7cef53bac textMetricsTest: added exception text for FF 68
Fixes #453
2020-03-18 14:06:34 +01:00
kkapsner
a9c89ff20c Version 1.3 2020-03-17 22:41:55 +01:00
kkapsner
d9d2038f0c
New Russian translations 2020-03-17 22:16:19 +01:00
kkapsner
f2b55fe7a2 Add missing APIs to ignoredAPIs 2020-03-17 20:04:28 +01:00
kkapsner
dd6fbc6c1f textMetricsTest: insert canvas in DOM 2020-03-15 13:43:41 +01:00
kkapsner
736aeb371d
New translations 2020-03-14 13:16:52 +01:00
kkapsner
ec128796e3 Added TextMetrics protection
Fixes #448
2020-03-14 12:54:23 +01:00
kkapsner
692b4616e2 Switch from .local to .localhost to simplify https setup 2020-03-14 11:05:02 +01:00
kkapsner
895f1a6f66 Avoid mixed content in test 2020-03-12 23:01:42 +01:00
kkapsner
73e5f5737b Added warning if some features of a API are disabled 2020-03-06 12:06:40 +01:00
kkapsner
d449e5f0c3 Added FAQ for reCAPTCHA
For #398
2020-02-27 17:30:58 +01:00
kkapsner
9614786406 New beta version 2020-02-25 08:44:01 +01:00
kkapsner
0f1aa1cc32 Always open options page in new tab
Fixes #434 and effects #445
2020-02-24 23:33:02 +01:00
kkapsner
13b061c395 Removed unnecessary activeTab permission 2020-02-23 16:43:17 +01:00
kkapsner
00f69b73ab
New Russian translations 2020-02-23 16:42:16 +01:00
kkapsner
1cfdcdb120 Added FAQs
For #106
2020-02-16 19:57:11 +01:00
kkapsner
73694ab129
Added Norwegian 2020-02-15 14:52:55 +01:00
kkapsner
59d78c8e68 New translations
New Italian and Chinese translations.
2020-02-09 23:49:42 +01:00
kkapsner
84e40b5eb4 Some code improvements
Fixes #439
2020-02-01 22:00:39 +01:00
kkapsner
ada2845213 Add task for alpha build 2020-02-01 22:00:13 +01:00
kkapsner
9e92e4baf2 Version 1.2 2020-01-29 10:42:52 +01:00
kkapsner
f65d73f125
New Italian translations 2020-01-29 10:41:43 +01:00
146 changed files with 31256 additions and 7595 deletions

View File

@ -1,5 +1,7 @@
Dieses Add-on ermöglicht es Nutzern, Webseiten davon abzuhalten, sie über Javascript APIs zu identifizieren. Nutzer können auswählen, ob die APIs komplett auf bestimmten oder allen Seiten blockiert werden (dies wird die Funktionalität einiger Seiten beeinträchtigen) oder bei den identifikationsfreundlichen Auslese-Funktionen falsche Werte vorzutäuschen.
Bei Problemen konsultieren Sie bitte zuerst <a href="https://canvasblocker.kkapsner.de/faq/">FAQ</a>. Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
<b>WICHTIG</b>: Sie sollten nur ein Addon/eine Einstellung aktiv haben, die eine API beschützt. Ansonsten können Sie massive Performanceprobleme bekommen. (Z.B. EclipsedMoon für Palemoon hat 'canvas.poison', was bekanntermaßen Probleme verursacht: https://github.com/kkapsner/CanvasBlocker/issues/253#issuecomment-459499290)
privacy.resistFingerprinting kann aber problemlos aktiviert werden und der Fingerprinting-Schutz muss nicht deaktiviert werden.
@ -11,6 +13,7 @@ Beschützte "Fingerprinting"-APIs:
<li>history</li>
<li>window (standardmäßig deaktiviert)</li>
<li>DOMRect</li>
<li>TextMetrics</li>
<li>navigator (standardmäßig deaktiviert)</li>
<li>screen</li>
</ul>
@ -39,6 +42,4 @@ Die verschiedenen Blockiermodi sind:
<li>nur Einträge der Whitelist erlauben: Nur Seiten, die in der Whitelist gelistet sind, dürfen die beschützten APIs verwenden.</li>
<li>nur Einträge der Blacklist blockieren: Blockiere die beschützten APIs nur auf den Seiten der Blacklist.</li>
<li>alles erlauben: Ignoriere alle Listen und erlaube die beschützten APIs auf allen Webseiten.</li>
</ul>
Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
</ul>

View File

@ -1,5 +1,7 @@
This add-on allows users to prevent websites from using some Javascript APIs to fingerprint them. Users can choose to block the APIs entirely on some or all websites (which may break some websites) or fake its fingerprinting-friendly readout API.
If you encounter any problems please check the <a href="https://canvasblocker.kkapsner.de/faq/">FAQ</a> first. Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues
<b>IMPORTANT</b>: you should only have ONE addon/setting set that protects an API. Otherwise you could face massive performance issues. (E.g. EclipsedMoon for Palemoon has 'canvas.poison' which is known to cause issues: https://github.com/kkapsner/CanvasBlocker/issues/253#issuecomment-459499290)
But setting privacy.resistFingerprinting to true and/or using the new fingerprinting protection introduced with Firefox 67 is fine.
@ -11,6 +13,7 @@ Protected "fingerprinting" APIs:
<li>history</li>
<li>window (disabled by default)</li>
<li>DOMRect</li>
<li>TextMetrics</li>
<li>navigator (disabled by default)</li>
<li>screen</li>
</ul>
@ -41,5 +44,3 @@ The different block modes are:
<li> block only black list: Block the protected APIs only for websites on the black list.</li>
<li> allow everything: Ignore all lists and allow the protected APIs on all websites.</li>
</ul>
Please report issues and feature requests at https://github.com/kkapsner/CanvasBlocker/issues

View File

@ -0,0 +1,12 @@
body {
margin: 30px auto;
max-width: 680px;
font-size: 13pt;
line-height: 1.4em;
color: #444444;
padding: 0;
}
h1, h2, h3{
line-height: 1.2em;
}

View File

@ -0,0 +1,9 @@
How is CanvasBlocker funded?
-------
There is no steady monetary funding of CanvasBlocker. Donations are accepted and help to cover some expenses. But since these are not that high it is not sure if a steady funding with any obligations will be accepted.
There is also no plan to monetize CanvasBlocker in any way.
All the development work is done by kkapsner in their spare time and no salary or compensation is paid for it.
So it's all done voluntarily for fun and free.

View File

@ -0,0 +1,5 @@
How can I support CanvasBlocker?
------
The best way to support CanvasBlocker is to give feedback. If something is not working like it should or something could be improved please open an [issue](https://github.com/kkapsner/CanvasBlocker/issues/new). Reviews at [addons.mozilla.org](https://addons.mozilla.org/firefox/addon/canvasblocker/reviews/) can also help to increase the user base but it is a very bad platform to communicate issues and improvements.
If you want to contribute with your own spare time you can help to improve the [translations](https://github.com/kkapsner/CanvasBlocker/issues/420). Code contributions can also be done in form of pull requests but will be reviewed very thoroughly.

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>
CanvasBlocker FAQs
</title>
<link rel="stylesheet" href="../default.css" type="text/css">
</head>
<body>
<header><h1>CanvasBlocker FAQs</h1></header>
<?php
include_once("../../kamiKatze/autoload.php");
$parser = new MarkdownParser();
foreach (new DirectoryIterator("./") as $file){
if (!$file->isDot() && !$file->isDir() && $file->getExtension() === "md"){
$markdown = $parser->parse(file_get_contents($file->getPathname()));
echo preg_replace("/<h2/", "<h2 id=\"" . str_replace(".md", "", $file->getFilename()) . "\"", $markdown->view("html"), 1);
}
}
?>
</body>
</html>

View File

@ -0,0 +1,9 @@
I do not find setting X.
------
Some settings are not always visible. There are three reasons why settings might be hidden:
* Some require other settings to be a certain value to be displayed because they are not useful without the other setting. E.g. the whole "Asking" section is only displayed when the block mode is set to "ask for permission".
* Other settings are hidden behind the "expert mode" because they need a certain level of understanding of CanvasBlocker to be used correctly.
* Finally you can hide settings. To show these settings you have to enable "display hidden settings".
So if you search for a setting and do not find it you should first enable the "expert mode" and "display hidden settings". If you then still do not find it it's not relevant for your current setup of CanvasBlocker.

View File

@ -0,0 +1,3 @@
PayPal transactions started with "Buy now" button not working!
-----
It's a known fact that the window API protection hinders the completion of all transaction processes initiated via PayPal's "Buy now" button. You have to whitelist paypal.com for that API for it to work properly.

View File

@ -0,0 +1,9 @@
Why does CanvasBlocker need permission X?
------
Here is the list of permission that CanvasBlocker needs and the reason why it's needed:
* <all_urls> and tabs: CanvasBlocker needs to be able to interact with all possible urls and tabs as fingerprinting attempts could be done everywhere.
* storage: to store the settings the storage.local API is used.
* webRequest and webRequestBlocking: to insert the CSR headers in a request in order to protect the data-URLs. Once [this bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1475831) has been fixed I can completely remove the data-URI protection (see [here](https://github.com/kkapsner/CanvasBlocker/issues/208) for further information).
* contextualIdentities and cookies: for support of browser containers. I would like to make this optional for only the people that use containers but I cannot (see [here](https://github.com/kkapsner/CanvasBlocker/issues/381) for further information).
* privacy: this permission is needed to read if the user has privacy.resistFingerprinting enabled. A notice about a slightly changed behaviour of CanvasBlocker is displayed in the settings page in that case.

View File

@ -0,0 +1,5 @@
reCAPTCHA is not working!
-----
It's a known fact that the window API protection breaks reCAPTCHAs. They use the window.name API to store information about the captcha. The protection is designed to mitigate exactly such techniques of passing information from one domain to another. But in this case the information is shared with an embedded HTML page (an <iframe> tag). As the information gets lost when the top level page navigates somewhere the tracking potential is quite limited in such a scenario.
So in conclusion you can enable "Allow window.name in frames" to make reCAPTCHA work and still don't have to worry too much about tracking with window.name.

View File

@ -0,0 +1,5 @@
How do I remove URL specific settings?
------
If one URL specific setting is set for a URL it shows up at every setting that can have URL specific values. So if you click on the little "x" to reset the value the line for the URL may not disappear. But the input field will appear a little bit gray to indicate that the "normal" value is still used for this URL.
To get rid of this URL line you have to remove all specific settings for this URL. The easiest way to get to know which settings are still set you can go to General > Settings > Export settings > Inspect. There the entry "urlSettings" stores the url specific values.

View File

@ -0,0 +1,10 @@
Page X claims my fingerprint is unique.
------
Having a unique fingerprint is fine as long as it changes. With the default settings of CanvasBlocker the fingerprint should change all the time. But also with other settings (e.g. the stealth preset) that do not change the fingerprint all the time the fingerprint should be unique per domain and therefore prevent tracking. To test this you can check the different fingerprints on [canvasblocker.kkapsner.de](https://canvasblocker.kkapsner.de/test/) and [canvasblocker2.kkapsner.de](https://canvasblocker2.kkapsner.de/test/).
My fingerprint does not change when I reload page X.
------
Some pages do not recalculate the fingerprint upon reload. Make sure you force the recomputation.
But also some CanvasBlocker settings make it to not change the fingerprint upon reload (e.g. the stealth preset).
If you have privacy.resistFingerprinting enabled the fingerprints also may stay the same. But in this case you are not trackable as the fingerprint does not leak any information about your system. See [here](https://github.com/kkapsner/CanvasBlocker/issues/158) and [here](https://github.com/ghacksuserjs/ghacks-user.js/issues/767) for further information.

View File

@ -2,13 +2,13 @@
## Description
<!--- Provide a more detailed introduction to the issue itself. -->
<!--- Why you consider it to be a bug or a usefull change/improvement? -->
<!--- Why you consider it to be a bug or a useful change/improvement? -->
## Expected Behavior
## Expected Behaviour
<!--- If you're describing a bug, tell us what should happen. -->
<!--- If you're suggesting a change/improvement, tell us how it should work. -->
## Current Behavior
## Current Behaviour
<!--- If describing a bug, tell us what happens instead of the expected behavior. -->
<!--- If suggesting a change/improvement, explain the difference from current behavior. -->
@ -18,10 +18,10 @@
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. -->
1.
2.
3.
4.
1. create a fresh Firefox profile
2.
3.
4.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
@ -36,6 +36,8 @@
* Installed addons:
## Your Settings
~~~ json
<!--- Copy your CanvasBlocker settings here. -->
<!-- They can be retrieved by checking the expert mode and going to export settings. -->
<!--- You may consider deleting personal data - especially the "persistentRndStorage". -->
<!--- You may consider deleting personal data - especially the "persistentRndStorage". -->
~~~

View File

@ -14,11 +14,53 @@ const args = yargs
const fs = require("fs");
function getAlphaVersion(manifest){
const versionsPath = path.join(__dirname, "..", "versions");
function getXPIFileName(id, version){
"use strict";
return `${id}-${version}.xpi`;
}
async function addAlphaVersionToUpdatesJSON(version){
"use strict";
const updatesPath = path.join(versionsPath, "updates.json");
const data = JSON.parse(await fs.promises.readFile(updatesPath));
const versions = data.addons["CanvasBlocker-Beta@kkapsner.de"].updates;
if (versions.some(function(entry){
return entry.version === version;
})){
return;
}
versions.push({
version,
update_link: `https://canvasblocker.kkapsner.de/versions/${getXPIFileName("canvasblocker_beta", version)}`
});
await fs.promises.writeFile(updatesPath, JSON.stringify(data, undefined, "\t"));
}
async function getAlphaVersion(manifest){
"use strict";
function f(n){
if (n < 10) return "0" + n.toString(10);
return n.toString(10);
}
const now = new Date();
const date = now.toISOString().substr(0, 10).replace(/-/g, "");
return manifest.version.replace(/^([\d.]+).*$/, "$1Alpha" + date);
const date = `${now.getFullYear()}${f(now.getMonth() + 1)}${f(now.getDate())}`;
const versionParts = manifest.version.split(".");
while (versionParts.length > 2){
versionParts.pop();
}
const baseVersion = `${versionParts.join(".")}.${date}`;
if (!fs.existsSync(path.join(versionsPath, getXPIFileName("canvasblocker_beta", baseVersion)))){
return baseVersion;
}
let dayTry = 1;
while (fs.existsSync(path.join(versionsPath, getXPIFileName("canvasblocker_beta", `${baseVersion}.${dayTry}`)))){
dayTry += 1;
}
return `${baseVersion}.${dayTry}`;
}
function getRCVersion(manifest){
"use strict";
@ -37,15 +79,22 @@ async function run(){
const manifest = require(manifestPath);
if (args.type === "alpha" || args.type === "rc"){
manifest.name = "CanvasBlocker-Beta";
manifest.applications.gecko.id = "CanvasBlocker-Beta@kkapsner.de";
["gecko", "gecko_android"].forEach(function(browserType){
if (!manifest.browser_specific_settings[browserType]) return;
manifest.browser_specific_settings[browserType].id = "CanvasBlocker-Beta@kkapsner.de";
});
}
else {
manifest.name = "CanvasBlocker";
manifest.applications.gecko.id = "CanvasBlocker@kkapsner.de";
delete manifest.applications.gecko.update_url;
["gecko", "gecko_android"].forEach(function(browserType){
if (!manifest.browser_specific_settings[browserType]) return;
manifest.browser_specific_settings[browserType].id = "CanvasBlocker@kkapsner.de";
delete manifest.browser_specific_settings[browserType].update_url;
});
}
if (args.type === "alpha"){
manifest.version = getAlphaVersion(manifest);
manifest.version = await getAlphaVersion(manifest);
addAlphaVersionToUpdatesJSON(manifest.version);
}
else if (args.type === "rc"){
manifest.version = getRCVersion(manifest);
@ -64,6 +113,8 @@ async function run(){
"--ignore-files",
"versions",
"--ignore-files",
"crowdin.yml",
"--ignore-files",
"package*"
];
const child = child_process.spawn("web-ext", childArgs, {stdio: "inherit"});

View File

@ -0,0 +1,164 @@
const data = require("./chromeVendors.json");
function addString(string, currentTree){
"use strict";
if (string.length <= 1){
const nextTree = currentTree[string] || {};
currentTree[string] = nextTree;
}
else {
const firstChar = string.substring(0, 1);
const nextTree = currentTree[firstChar] || {};
currentTree[firstChar] = nextTree;
const nextString = string.substring(1);
addString(nextString, nextTree);
}
}
function output(tree){
"use strict";
const keys = Object.keys(tree);
switch (keys.length){
case 0:
return "";
case 1:
return keys[0] + output(tree[keys[0]]);
default:
return "<" + keys.map(key => key + output(tree[key])).join("|") + ">";
}
}
// every string ends with a ) and does not contain <, >, $ or |
data.forEach(function(string){
"use strict";
if (
!string.endsWith(")") ||
string.match(/[<>|$]/)
){
throw string;
}
});
const tree1 = {};
const tree2 = {};
const tree3 = {};
data.every(function(string){
"use strict";
string = string.substring(0, string.length - 1);
const parts = string.split(" Direct", 2);
const parts2 = parts[0].split(" (Microsoft Corporation", 2);
addString(parts2[0], tree1);
if (parts2.length > 1){
addString(" (Microsoft Corporation" + parts2[1], tree2);
}
else {
addString("", tree2);
}
if (parts.length > 1){
addString(" Direct" + parts[1], tree3);
}
else {
addString("", tree3);
}
return true;
});
// const compressed = output(tree1) + output(tree2) + output(tree3) + ")";
const compressed = output(tree1) + output(tree2) +
"< Direct3D<11 vs_<4_<0 ps_4_0|1 ps_4_1>|5_0 ps_5_0>|9<Ex|> vs_<0_0 ps_<2_0|3_0>|2_0 ps_2_0|3_0 ps_3_0>>|>" + ")";
console.log("compressed length", compressed.length);
// console.log(compressed);
function countWords(string){
"use strict";
const words = {};
string.split(/[^0-9a-z]+/i).filter(word => word.length > 2).forEach(function(word){
const wordStats = words[word] || {count: 0};
words[word] = wordStats;
wordStats.count += 1;
});
return words;
}
function wordCompressor(string){
"use strict";
const words = countWords(string);
const duplicatedWord = Object.keys(words)
.map(function(word){
return {
word,
count: words[word].count
};
})
.filter(word => word.count > 1)
.sort((a, b) => b.word.length*b.count - a.word.length*a.count);
let compressed = string;
let index = 0;
const usedWords = [];
for (let i = 0; i < duplicatedWord.length; i += 1){
const replacement = "$" + index.toString(36);
const word = duplicatedWord[i].word;
if (
replacement.length < word.length &&
(word.length - replacement.length) * duplicatedWord[i].count > word.length + 1
){
compressed = compressed.replace(new RegExp("\\b" + word + "\\b", "g"), replacement);
index += 1;
usedWords.push(word);
}
}
return {compressed, usedWords};
}
const {compressed: compressed2, usedWords} = wordCompressor(compressed);
console.log("compressed 2 length", compressed2.length);
console.log(compressed2);
console.log(usedWords.join("|"));
function decompress(string, words){
"use strict";
return string.replace(/\$([0-9a-z]+)/gi, function(m, index){
return words[parseInt(index, 36)];
});
}
const decompressed2 = decompress(compressed2, usedWords);
console.log("test: ", compressed === decompressed2);
for (let start = 0; start < compressed.length; start += 100){
if (compressed.substring(start, start + 100) !== decompressed2.substring(start, start + 100)){
console.log(start);
console.log(compressed.substring(start, start + 100));
console.log(decompressed2.substring(start, start + 100));
}
}
function pickOne(string){
"use strict";
const options = [];
let cumulate = "";
let index = 0;
for (const l = string.length; index < l; index += 1){
const char = string.charAt(index);
if (char === "|"){
options.push(cumulate);
cumulate = "";
}
else if (char === "<"){
const subPick = pickOne(string.substring(index + 1));
cumulate += subPick.value;
index += 1 + subPick.endIndex;
}
else if (char === ">"){
break;
}
else {
cumulate += char;
}
}
options.push(cumulate);
return {value: options[Math.floor(Math.random() * options.length)], endIndex: index};
}
console.log(pickOne(compressed).value);

693
.tools/chromeVendors.json Normal file
View File

@ -0,0 +1,693 @@
[
"ANGLE (AMD (ATI) FirePro M8900 (FireGL) Mobility Pro Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD 760G (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD 760G Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD 760G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD FirePro 2270 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD FirePro W5000 (FireGL V) Graphics Adapter Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD M880G with ATI Mobility Radeon HD 4200 )",
"ANGLE (AMD M880G with ATI Mobility Radeon HD 4200 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD M880G with ATI Mobility Radeon HD 4250 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5670 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 5800 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6250 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6250M )",
"ANGLE (AMD Radeon HD 6290 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6290 Graphics (Microsoft Corporation- WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6290 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6300 series Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6310 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6310 Graphics )",
"ANGLE (AMD Radeon HD 6310 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6310M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6320 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6320 Graphic Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6320 Graphics )",
"ANGLE (AMD Radeon HD 6320 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6320 Graphics)",
"ANGLE (AMD Radeon HD 6320 series Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6320M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6350 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6370D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6370M)",
"ANGLE (AMD Radeon HD 6400M Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6410D Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6410D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6450 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6450A Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6470M )",
"ANGLE (AMD Radeon HD 6470M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6470M)",
"ANGLE (AMD Radeon HD 6480G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6500M/5600/5700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6510 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6520G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6530D Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6550A Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6570 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6570)",
"ANGLE (AMD Radeon HD 6620G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6630M)",
"ANGLE (AMD Radeon HD 6650A Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6670 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6730M)",
"ANGLE (AMD Radeon HD 6800 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6800 Series)",
"ANGLE (AMD Radeon HD 6900 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 6900M Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7000 series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7290 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7300 Series Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7300 Series)",
"ANGLE (AMD Radeon HD 7310 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7310 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7310M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7340 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7340 Graphics (Microsoft Corporation - WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7340 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7340G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7340M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7400M Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7420G Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7420G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7450 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7470M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7480D Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7480D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7500/7600 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7500G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7500M/7600M Series (Microsoft Corporation - WDDM v1.3) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7520G + 7670M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7520G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7540D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7550M/7650M Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7550M/7650M Graphics)",
"ANGLE (AMD Radeon HD 7560D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7570 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7570M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7580D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7600G + 6400M Dual Graphics)",
"ANGLE (AMD Radeon HD 7600M Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7610M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7610M)",
"ANGLE (AMD Radeon HD 7640G + 7600M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7640G + 7670M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7640G + 8750M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7640G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7650M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7660D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7660D)",
"ANGLE (AMD Radeon HD 7660G + 7600M Dual Graphics)",
"ANGLE (AMD Radeon HD 7660G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7670M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7700 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7800 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 7800 Series)",
"ANGLE (AMD Radeon HD 7900 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8210 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8240 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8250 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8330 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8350 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8400 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8450G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8470 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8470D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8510G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8550G + 8570M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8550G + HD 8600/8700M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8550G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8570D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8610G + 8500M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8610G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8650G + 8670M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8650G + 8750M Dual Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD 8670D Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD6370D Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD6410D Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD7700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon HD7770 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon R7 200 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon R9 200 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon(TM) HD 6380G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon(TM) HD 6480G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon(TM) HD 6520G )",
"ANGLE (AMD Radeon(TM) HD 6520G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon(TM) HD 6620G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (AMD Radeon(TM) HD 7450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH4350 series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH5450 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH5670 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH5770 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH6450 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH6670 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS EAH6970 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS HD7770 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ASUS R9 270 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI FirePro 2450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI FirePro V3700 (FireGL) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI FirePro V3800 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI FirePro V4800 (FireGL) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon 9600/9700 Series)",
"ANGLE (ATI Mobility Radeon HD 2400 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 2400 XT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 2600 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 3400 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 3430 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 3450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 3470 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 3650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4200 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4200 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4250 )",
"ANGLE (ATI Mobility Radeon HD 4250 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4250 Graphics Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4250 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4300 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4300/4500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4330 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4330)",
"ANGLE (ATI Mobility Radeon HD 4500 Series (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4500/5100 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4530 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4570)",
"ANGLE (ATI Mobility Radeon HD 4650 (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 4650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5000 Series (Microsoft Corporation - WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5000 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5145 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5400 Series )",
"ANGLE (ATI Mobility Radeon HD 5400 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5430)",
"ANGLE (ATI Mobility Radeon HD 5450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 545v Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5470 )",
"ANGLE (ATI Mobility Radeon HD 5470 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5470 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5470)",
"ANGLE (ATI Mobility Radeon HD 5650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon HD 5650)",
"ANGLE (ATI Mobility Radeon HD 6370)",
"ANGLE (ATI Mobility Radeon HD 6550 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon X1300 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon X1600 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Mobility Radeon X1600)",
"ANGLE (ATI Radeon 2100 (Microsoft Corporation - WDDM) Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon 2100 Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon 2100)",
"ANGLE (ATI Radeon 3000 Graphics (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon 3000 Graphics Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon 3000 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon 3000 Graphics)",
"ANGLE (ATI Radeon 3100 Graphics (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon 3100 Graphics)",
"ANGLE (ATI Radeon HD 2350 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 Pro )",
"ANGLE (ATI Radeon HD 2400 Pro Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 PRO Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 Pro Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 PRO Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 XT (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 XT )",
"ANGLE (ATI Radeon HD 2400 XT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 XT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2400 XT)",
"ANGLE (ATI Radeon HD 2600 Pro )",
"ANGLE (ATI Radeon HD 2600 PRO)",
"ANGLE (ATI Radeon HD 2600 XT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 2600 XT)",
"ANGLE (ATI Radeon HD 3200 Graphics (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3200 Graphics Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3200 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3300 Graphics Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3300 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3400 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3400 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3450 - Dell Optiplex Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3450 - Dell Optiplex Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3450 (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3470 - Dell Optiplex Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3600 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3600 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 3800 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4200 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4200 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4200)",
"ANGLE (ATI Radeon HD 4250 )",
"ANGLE (ATI Radeon HD 4250 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4250 Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4250)",
"ANGLE (ATI Radeon HD 4300 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4300/4500 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4350 (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4350 )",
"ANGLE (ATI Radeon HD 4350 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4350 Series)",
"ANGLE (ATI Radeon HD 4350)",
"ANGLE (ATI Radeon HD 4550 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4600 Series (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4600 Series )",
"ANGLE (ATI Radeon HD 4600 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4600 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4600 Serisi (Microsoft Corporation- WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4650 (Microsoft Corporation WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4670)",
"ANGLE (ATI Radeon HD 4770 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4800 Series (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4800 Series (Microsoft Corporation WDDM 1.1) )",
"ANGLE (ATI Radeon HD 4800 Series Direct3D11 vs_4_1 ps_4_1)",
"ANGLE (ATI Radeon HD 4800 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4800 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 4800 Series)",
"ANGLE (ATI Radeon HD 4870 X2 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5400 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5450 (Microsoft Corporation - WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5450 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5450)",
"ANGLE (ATI Radeon HD 5570 (Microsoft Corporation - WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5600 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5670 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5700 Series (Microsoft Corporation - WDDM v1.20) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5700 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5700 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 5800 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 6230 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD 6350 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon HD4670 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (ATI Radeon X1050 Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1050 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1200 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1200 Series (Microsoft Corporation - WDDM) Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1200 Series Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1200 Series Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1200 Series)",
"ANGLE (ATI Radeon X1250 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X1270 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X300/X550/X1050 Series Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X300/X550/X1050 Series Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon X300/X550/X1050 Series)",
"ANGLE (ATI Radeon Xpress 1100 Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 1150 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 1150 Series Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 1150 Series Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 1200 Series Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 1250 Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (ATI Radeon Xpress 200 Series Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (Intel(R) 4 Series Internal Chipset Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Intel(R) 4 Series Internal Chipset Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) 82915G/GV/910GL Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) 82945G Express Chipset Family (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) 82945G Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) 82945G Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) 82945G Express Chipset Family)",
"ANGLE (Intel(R) 946GZ Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) 946GZ Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) B43 Express Chipset Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G33/G31 Express Chipset Family (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) G33/G31 Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) G33/G31 Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) G33/G31 Express Chipset Family)",
"ANGLE (Intel(R) G41 Express Chipset (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G41 Express Chipset (Microsoft Corporation - WDDM 1.1))",
"ANGLE (Intel(R) G41 Express Chipset Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G41 Express Chipset Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G41 Express Chipset)",
"ANGLE (Intel(R) G45/G43 Express Chipset (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G45/G43 Express Chipset Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) G965 Express Chipset Family Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) Graphics Media Accelerator 3150 (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Graphics Media Accelerator 3150 Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Graphics Media Accelerator 3150 Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Graphics Media Accelerator 3150)",
"ANGLE (Intel(R) Graphics Media Accelerator 3600 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) Graphics Media Accelerator HD )",
"ANGLE (Intel(R) Graphics Media Accelerator HD Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics 3000 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics 3000)",
"ANGLE (Intel(R) HD Graphics 4000 (Microsoft Corporation - WDDM 1.2) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics 4000 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics 4000)",
"ANGLE (Intel(R) HD Graphics 4400 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics 4600 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics Family Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics Family Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) HD Graphics Family)",
"ANGLE (Intel(R) HD Graphics)",
"ANGLE (Intel(R) Q33 Express Chipset Family (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q33 Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q33 Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q35 Express Chipset Family (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q35 Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q35 Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q45/Q43 Express Chipset (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) Q45/Q43 Express Chipset (Microsoft Corporation - WDDM 1.1))",
"ANGLE (Intel(R) Q45/Q43 Express Chipset Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Intel(R) Q45/Q43 Express Chipset Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Intel(R) Q45/Q43 Express Chipset)",
"ANGLE (Intel(R) Q965/Q963 Express Chipset Family (Microsoft Corporation - WDDM 1.0) Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q965/Q963 Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q965/Q963 Express Chipset Family Direct3D9Ex vs_0_0 ps_2_0)",
"ANGLE (Intel(R) Q965/Q963 Express Chipset Family)",
"ANGLE (Microsoft Basic Render Driver Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) - famiglia Express Chipset 45 (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 4 Series Express Chipset Family (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 4 Series Express Chipset Family Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 4 Series Express Chipset Family Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 4 Series Express Chipset Family)",
"ANGLE (Mobile Intel(R) 45 Express Chipset Family (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family Direct3D9 vs_0_0 ps_2_0)",
"ANGLE (Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family)",
"ANGLE (Mobile Intel(R) 945 Express Chipset Family)",
"ANGLE (Mobile Intel(R) 945GM Express Chipset Family)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family (Microsoft Corporation - WDDM 1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family Direct3D9 vs_0_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family Direct3D9Ex vs_0_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) 965 Express Chipset Family)",
"ANGLE (Mobile Intel(R) HD Graphics Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Mobile Intel(R) HD Graphics)",
"ANGLE (NVIDIA GeForce 210 )",
"ANGLE (NVIDIA GeForce 210 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 210 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 210)",
"ANGLE (NVIDIA GeForce 310 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 310M (Microsoft Corporation - WDDM v1.2) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 310M )",
"ANGLE (NVIDIA GeForce 310M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 310M)",
"ANGLE (NVIDIA GeForce 315 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 315M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 405 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 405)",
"ANGLE (NVIDIA GeForce 405M)",
"ANGLE (NVIDIA GeForce 410M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 605 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6100 nForce 405 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6100 nForce 405 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6100)",
"ANGLE (NVIDIA GeForce 610M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150 LE (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150 LE Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150SE nForce 430 (Microsoft Corporation - WDDM v1.2) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150SE nForce 430 (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150SE nForce 430 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150SE nForce 430 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6150SE nForce 430)",
"ANGLE (NVIDIA GeForce 6200 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6200 TurboCache(TM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6500 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6600 (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6600 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 6600 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7000M / nForce 610M Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7000M / nForce 610M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7025 / NVIDIA nForce 630a (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7025 / NVIDIA nForce 630a )",
"ANGLE (NVIDIA GeForce 7025 / NVIDIA nForce 630a Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7025 / NVIDIA nForce 630a Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7025 / NVIDIA nForce 630a)",
"ANGLE (NVIDIA GeForce 7050 / NVIDIA nForce 620i Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7050 PV / NVIDIA nForce 630a Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7100 / NVIDIA nForce 630i Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7100 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7150M / nForce 630M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 GS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 GT (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 LE (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 LE Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 SE/7200 GS (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 SE/7200 GS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7300 SE/7200 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 7900 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8200 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8200M G Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8200M G)",
"ANGLE (NVIDIA GeForce 8300 GS )",
"ANGLE (NVIDIA GeForce 8300 GS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8300 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400 GS (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400 GS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400 GS)",
"ANGLE (NVIDIA GeForce 8400GS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400M GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8400M GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8500 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8500 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GT (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GT )",
"ANGLE (NVIDIA GeForce 8600 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GT)",
"ANGLE (NVIDIA GeForce 8600 GTS (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GTS Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600 GTS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600GS (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600M GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8600M GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8800 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8800 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8800 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8800 GTS 512 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 8800 GTS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9100 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9200 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9200M GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9300 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9300 GE (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9300 GE Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9300 GE Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9300M GS (Microsoft Corporation - WDDM v1.1))",
"ANGLE (NVIDIA GeForce 9300M GS )",
"ANGLE (NVIDIA GeForce 9300M GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9400 GT (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9400 GT )",
"ANGLE (NVIDIA GeForce 9400 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9400 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9400 GT)",
"ANGLE (NVIDIA GeForce 9400M )",
"ANGLE (NVIDIA GeForce 9500 GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9500 GS)",
"ANGLE (NVIDIA GeForce 9500 GT (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9500 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9500 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9500 GT)",
"ANGLE (NVIDIA GeForce 9500M GS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9600 GSO 512 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9600 GT (Microsoft Corporation - WDDM v1.1))",
"ANGLE (NVIDIA GeForce 9600 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9600 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9600 GT)",
"ANGLE (NVIDIA GeForce 9600M GS)",
"ANGLE (NVIDIA GeForce 9600M GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9600M GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9650M GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9700M GTS Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9800 GT (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9800 GT (Microsoft Corporation - WDDM v1.1))",
"ANGLE (NVIDIA GeForce 9800 GT )",
"ANGLE (NVIDIA GeForce 9800 GT Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9800 GT Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce 9800 GTX/9800 GTX+ Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce FX 5200 Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (NVIDIA GeForce G 103M )",
"ANGLE (NVIDIA GeForce G 105M )",
"ANGLE (NVIDIA GeForce G 105M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce G100 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce G100)",
"ANGLE (NVIDIA GeForce G102M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce G105M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce G210 )",
"ANGLE (NVIDIA GeForce G210 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce G210)",
"ANGLE (NVIDIA GeForce G210M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce Go 7300 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 120M)",
"ANGLE (NVIDIA GeForce GT 220 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 220 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 220)",
"ANGLE (NVIDIA GeForce GT 230 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 230M )",
"ANGLE (NVIDIA GeForce GT 230M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 240 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 240 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 240)",
"ANGLE (NVIDIA GeForce GT 240M )",
"ANGLE (NVIDIA GeForce GT 240M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 320 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 320M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 330 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 330M )",
"ANGLE (NVIDIA GeForce GT 330M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 335M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 420 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 420M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 425M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 430 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 430 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 430)",
"ANGLE (NVIDIA GeForce GT 440 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 440 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 440)",
"ANGLE (NVIDIA GeForce GT 520 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 520 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 520)",
"ANGLE (NVIDIA GeForce GT 520M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 520M)",
"ANGLE (NVIDIA GeForce GT 525M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 530 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 545 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 555M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 610 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 610)",
"ANGLE (NVIDIA GeForce GT 620 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 620)",
"ANGLE (NVIDIA GeForce GT 625 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 630 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 630 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 630M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 635 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 640 )",
"ANGLE (NVIDIA GeForce GT 640 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 640)",
"ANGLE (NVIDIA GeForce GT 640M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 650M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 740M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GT 755M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 240 Direct3D11 vs_4_0 ps_4_0)",
"ANGLE (NVIDIA GeForce GTS 250 (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 250 (Microsoft Corporation - WDDM v1.1))",
"ANGLE (NVIDIA GeForce GTS 250 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 250 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 250)",
"ANGLE (NVIDIA GeForce GTS 350M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 450 )",
"ANGLE (NVIDIA GeForce GTS 450 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 450 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTS 450)",
"ANGLE (NVIDIA GeForce GTX 260 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 275 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 285 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 295 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 460 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 460 SE Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 460)",
"ANGLE (NVIDIA GeForce GTX 460M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 480 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 550 Ti Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 550 Ti)",
"ANGLE (NVIDIA GeForce GTX 560 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 560 Ti )",
"ANGLE (NVIDIA GeForce GTX 560 Ti Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 560M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 570 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 580 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 580M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 650 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 650 Ti BOOST Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 650 Ti Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 650)",
"ANGLE (NVIDIA GeForce GTX 660 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 660 Ti Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 660M )",
"ANGLE (NVIDIA GeForce GTX 660M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 670 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 670)",
"ANGLE (NVIDIA GeForce GTX 675M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 680 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 690 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 760 (192-bit) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 760 Direct3D11 vs_5_0 ps_5_0)",
"ANGLE (NVIDIA GeForce GTX 760 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 770 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA GeForce GTX 780 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA ION Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA MCP67M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA nForce 750a SLI Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 300 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 3100M )",
"ANGLE (NVIDIA NVS 3100M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 4200M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 5100M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 5200M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA NVS 5400M )",
"ANGLE (NVIDIA Quadro 1000M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro 2000M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro 600 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 1500M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 1700 (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 1700 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 1800 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 2500M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 2700M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 3700 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 570 (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 570 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 580 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 770M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro FX 880M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro K3000M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro K600 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 110M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 135M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 140M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 140M)",
"ANGLE (NVIDIA Quadro NVS 160M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 160M)",
"ANGLE (NVIDIA Quadro NVS 285 Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 290 (Microsoft Corporation - WDDM v1.1) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (NVIDIA Quadro NVS 290 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon (TM) HD 6470M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon (TM) HD 6490M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon HD 6470M Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1300/X1550 Series (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1300/X1550 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Radeon X1300/X1550 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1550 64-bit (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1550 Series (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1650 SE Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1650 Series (Microsoft Corporation - WDDM) Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1650 Series )",
"ANGLE (Radeon X1650 Series Direct3D9 vs_3_0 ps_3_0)",
"ANGLE (Radeon X1650 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X1950 Series Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Radeon X300/X550/X1050 Series (Microsoft Corporation - WDDM) Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (Radeon X300/X550/X1050 Series Direct3D9 vs_2_0 ps_2_0)",
"ANGLE (Radeon X800 GTO (Microsoft Corporation - WDDM) Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (RDPDD Chained DD Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (Royal BNA Driver Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (RS880 Direct3D9Ex vs_3_0 ps_3_0)",
"ANGLE (SiS Mirage 3 Graphics Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (SiS Mirage 3 Graphics)",
"ANGLE (VIA Chrome9 HC IGP Family WDDM Direct3D9Ex vs_2_0 ps_2_0)",
"ANGLE (WinFast GT 640(NVIDIA) Direct3D9Ex vs_3_0 ps_3_0)"
]

65
.vscode/settings.json vendored
View File

@ -1,57 +1,63 @@
{
"cSpell.words": [
"arial",
"Benachrichtigungsdetails",
"benachrichtigungsicon",
"Blockiermodi",
"Blockiermodus",
"canvasblocker",
"Captcha",
"checkmark",
"collapser",
"Coord",
"darkgreen",
"dont",
"fakeable",
"Fenix",
"fragmenter",
"Funktionalitätstest",
"Funktionalitätstests",
"graytext",
"Hyrp",
"iframe",
"ignorelist",
"Ignorierliste",
"KHTML",
"Krasnaya",
"lightgray",
"Maleficient",
"mediump",
"micrococo",
"monero",
"monospace",
"Nachfrageverweigerungsmodus",
"nocanvas",
"Oakenpants",
"PDFs",
"onedrive",
"onloaded",
"oscpu",
"Palemoon",
"paypal",
"PDFs",
"Ploshchad",
"prefs",
"promisify",
"recaptcha",
"Rect",
"Rects",
"ruleset",
"spodermenpls",
"Spoofer",
"statechange",
"Strg",
"SVGAPI",
"Thorin",
"Tiie",
"unticking",
"Vortäuschaktion",
"Vortäuschgröße",
"Vortäuschrate",
"Waterfox",
"arial",
"benachrichtigungsicon",
"canvasblocker",
"collapser",
"darkgreen",
"dont",
"fakeable",
"fragmenter",
"graytext",
"iframe",
"ignorelist",
"lightgray",
"mediump",
"micrococo",
"monero",
"nocanvas",
"onedrive",
"onloaded",
"oscpu",
"prefs",
"promisify",
"recaptcha",
"ruleset",
"spodermenpls",
"unticking",
"webgl",
"whitelisted",
"writeln",
@ -65,13 +71,14 @@
"**/vscode-extension/**",
"**/.git/objects/**",
".vscode",
".eslintrc.json"
".eslintrc.json",
".tools/chromeVendors.json"
],
"eslint.validate": [
"javascript",
"php",
"html"
],
"eslint.options": {"--ext": ".js,.html,.php"},
"eslint.lintTask.enable": true
"eslint.lintTask.enable": true,
"cSpell.enabled": true
}

35
.vscode/tasks.json vendored
View File

@ -45,7 +45,7 @@
"-f",
"nightly",
"--url",
"http://canvasblocker.local/test/"
"http://canvasblocker.localhost/test/"
],
"presentation": {
"echo": true,
@ -70,7 +70,7 @@
"args": [
"run",
"--url",
"http://canvasblocker.local/test/"
"http://canvasblocker.localhost/test/"
],
"presentation": {
"echo": true,
@ -97,7 +97,7 @@
"-f",
"firefox-esr",
"--url",
"http://canvasblocker.local/test/"
"http://canvasblocker.localhost/test/"
],
"presentation": {
"echo": true,
@ -124,7 +124,7 @@
"-f",
"firefox-beta",
"--url",
"http://canvasblocker.local/test/"
"http://canvasblocker.localhost/test/"
],
"presentation": {
"echo": true,
@ -154,6 +154,8 @@
"--ignore-files",
"versions",
"--ignore-files",
"crowdin.yml",
"--ignore-files",
"package*"
],
"presentation": {
@ -164,6 +166,31 @@
},
"problemMatcher": []
},
{
"label": "build alpha",
"type": "shell",
"windows": {
"command": "node"
},
"linux": {
"command": "node"
},
"osx": {
"command": "node"
},
"args": [
".tools/build.js",
"--type",
"alpha"
],
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
},
"problemMatcher": []
},
{
"label": "web-ext lint",
"type": "shell",

View File

@ -4,7 +4,7 @@ CanvasBlocker [![codebeat badge](https://codebeat.co/badges/0edd6c9f-250a-4f1e-9
This add-on allows users to prevent websites from using some Javascript APIs to fingerprint them. Users can choose to block the APIs entirely on some or all websites (which may break some websites) or just block or fake its fingerprinting-friendly readout API.
**IMPORTANT**: you should only have ONE addon/setting set that protects an API. Otherwise you could face massive performance issues. (E.g. EclipsedMoon for Palemoon has 'canvas.poison' which is known to cause issues: https://github.com/kkapsner/CanvasBlocker/issues/253#issuecomment-459499290)
But setting privacy.resistFingerprinting to true is fine.
But setting privacy.resistFingerprinting to true and/or using the new fingerprinting protection introduced with Firefox 67 is fine.
-----
@ -15,11 +15,13 @@ Protected "fingerprinting" APIs:
* history
* window (disabled by default)
* DOMRect
* SVG
* TextMetrics
* navigator (disabled by default)
* screen
More information on fingerprinting can be found at:
* &lt;canvas&gt;: http://www.browserleaks.com/canvas
* &lt;canvas&gt;: https://www.browserleaks.com/canvas
* audio:
* https://audiofingerprint.openwpm.com/ (very poorly written = slow)
* https://webtransparency.cs.princeton.edu/webcensus/#audio-fp
@ -60,4 +62,4 @@ Special thanks to:
If you want to support this addon you can donate to the following addresses:
* bitcoin: 159Y9BLcfHyrp6wj6f3syEuk92xkRVTiie
* bitcoin cash:qrchnszkdwv9knhg9wjucrqy43rpl4klkq7jhkc8dz
* monero: 482QYZaagALWtPmwbptwBaexDYmcVsJrhJp2VVjTgjYA3Kk1YyMdSg9Wz2qz1Gh31E843PFVCDWS4hR4Bjf6ipWuB9iz2cs
* monero: 482QYZaagALWtPmwbptwBaexDYmcVsJrhJp2VVjTgjYA3Kk1YyMdSg9Wz2qz1Gh31E843PFVCDWS4hR4Bjf6ipWuB9iz2cs

1670
_locales/cs/messages.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
"description": ""
},
"addon_description": {
"message": "Verändert einige JS-APIs um Fingerprinting zu verhindern.",
"message": "Verändert einige JS-APIs, um Fingerprinting zu verhindern.",
"description": ""
},
"browserAction_title_default": {
@ -23,6 +23,14 @@
"message": "\n · {api}",
"description": ""
},
"browserAction_status_on": {
"message": "CanvasBlocker an",
"description": ""
},
"browserAction_status_off": {
"message": "CanvasBlocker aus",
"description": ""
},
"more": {
"message": "mehr",
"description": ""
@ -64,7 +72,7 @@
"description": ""
},
"options_title": {
"message": "CanvasBlocker Einstellungen",
"message": "CanvasBlocker-Einstellungen",
"description": ""
},
"optionsIntroduction": {
@ -87,10 +95,18 @@
"message": "Sie haben privacy.resistFingerprinting aktiviert. Dies verändert das Verhalten von CanvasBlocker ein wenig. Weitere Informationen finden Sie {link:hier:https://github.com/kkapsner/CanvasBlocker/issues/158} und {link:hier:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"description": ""
},
"settingsNotice.dom.webAudio.enabled": {
"message": "Sie haben dom.webAudio.enabled deaktiviert. Da sehr wenige das tun, macht Sie das mehr nachverfolgbar.",
"description": ""
},
"openInTab": {
"message": "In separatem Tab öffnen",
"description": ""
},
"labelForDefaultOption": {
"message": " (Standard)",
"description": ""
},
"group_general": {
"message": "Allgemein",
"description": ""
@ -100,7 +116,7 @@
"description": ""
},
"group_misc": {
"message": "Vermischtes",
"message": "Sonstiges",
"description": ""
},
"section_asking": {
@ -120,7 +136,7 @@
"description": ""
},
"section_misc": {
"message": "Vermischtes",
"message": "Sonstiges",
"description": ""
},
"section_settings": {
@ -147,6 +163,14 @@
"message": "DOMRect-API",
"description": ""
},
"section_SVG-api": {
"message": "SVG-API",
"description": ""
},
"section_TextMetrics-api": {
"message": "TextMetrics-API",
"description": ""
},
"section_Navigator-api": {
"message": "Navigator-API",
"description": ""
@ -171,6 +195,26 @@
"message": "Zeigt die Beschreibungen der Einstellungen an.",
"description": ""
},
"disruptSessionOnUpdate_title": {
"message": "Aktualisierung unterbricht Sitzung",
"description": ""
},
"disruptSessionOnUpdate_description": {
"message": "Die Erweiterung wird sofort aktualisiert, sobald ein Update verfügbar ist, wenn aktiviert. Dies könnte einige Tabs unbrauchbar machen, die derzeit geöffnet sind.",
"description": ""
},
"reloadExtension_title": {
"message": "Erweiterung neu laden",
"description": ""
},
"reloadExtension_description": {
"message": "Führt eine ausstehende Aktualisierung aus.",
"description": ""
},
"reloadExtension_label": {
"message": "Neu laden",
"description": ""
},
"hideSetting": {
"message": "Hier klicken, um diese Einstellung zu verbergen.",
"description": ""
@ -267,6 +311,30 @@
"message": "Wollen Sie das Auslesen über die DOMRect-API erlauben?",
"description": ""
},
"askForSVGPermission": {
"message": "Wollen Sie die SVG-API erlauben?",
"description": ""
},
"askForSVGInputPermission": {
"message": "Wollen Sie das Schreiben über die SVG-API erlauben?",
"description": ""
},
"askForSVGReadoutPermission": {
"message": "Wollen Sie das Auslesen über die SVG-API erlauben?",
"description": ""
},
"askForTextMetricsPermission": {
"message": "Wollen Sie die TextMetrics-API erlauben?",
"description": ""
},
"askForTextMetricsInputPermission": {
"message": "Wollen Sie das Schreiben über die TextMetrics-API erlauben?",
"description": ""
},
"askForTextMetricsReadoutPermission": {
"message": "Wollen Sie das Auslesen über die TextMetrics-API erlauben?",
"description": ""
},
"askForNavigatorPermission": {
"message": "Wollen Sie die Navigator-API erlauben?",
"description": ""
@ -440,7 +508,7 @@
"description": ""
},
"rng_description": {
"message": "nichts (komplett weiß): es wird immer ein weißes Bild zurückgegeben. Hierbei sollte die Option \"Alpha-Kanal auch vortäuschen\" aktiviert werden. ACHTUNG: Nicht im Modus \"Bei Ausgabe vortäuschen\" verwenden.\n\nnicht persistent: die Zufallszahlen werden bei jeder Vortäuschaktion neu bestimmt.\n\nkonstant: innerhalb einer Webseite wird eine Farbe immer gleich verändert.\n\npersistent: für jede Domain werden die Zufallszahlen nur einmal bestimmt.",
"message": "nichts (komplett weiß): es wird immer ein weißes Bild zurückgegeben. Hierbei sollte die Option \"Alpha-Kanal auch vortäuschen\" aktiviert werden. ACHTUNG: Nicht im Modus \"Bei Ausgabe vortäuschen\" verwenden.\n\nnichtpersistent: die Zufallszahlen werden bei jeder Vortäuschaktion neu bestimmt. Beachten Sie, dass für viele APIs ein Zwischenspeicher verwendet wird, um eine Detektion zu verhindern.\n\nkonstant: Variante von nichtpersistent. Wenn die Daten eines Canvas verändert werden, haben gleichfarbige Pixel danach auch die gleiche Farbe.\n\npersistent: für jede Domain werden die Zufallszahlen nur einmal bestimmt.",
"description": ""
},
"rng_options.persistent": {
@ -452,7 +520,7 @@
"description": ""
},
"rng_options.nonPersistent": {
"message": "nicht persistent",
"message": "nichtpersistent",
"description": ""
},
"rng_options.white": {
@ -576,7 +644,7 @@
"description": ""
},
"webGLVendor_description": {
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"vendor\" verwendet. Leer lassen, um den Originalwert zu verwenden.",
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"vendor\" verwendet. Spezielle Werte:\nLeer lassen, um den Originalwert zu verwenden\n\n{undefined}: gibt undefined zurück (#508)\n\n{false}: gibt den Wahrheitsert falsch zurück (#508)\n\n{empty}: gibt eine leere Zeichenkette zurück(#508)\n\n{disabled}: gibt null zurück (#508)\n\n{random vendor}: gibt einen zufälligen \"vendor\" aus der eingebauten Liste zurück (#493)\n\n{random renderer}: gibt einen zufälligen \"renderer\" aus der eingebauten Liste zurück (#493)\n\n<xxx|yyy|zzz>: wählt zufällig eine der Optionen xxx, yyy oder zzz aus (beliebige Anzahl von Optionen) (#493)",
"description": ""
},
"webGLRenderer_title": {
@ -584,7 +652,7 @@
"description": ""
},
"webGLRenderer_description": {
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"renderer\" verwendet. Leer lassen, um den Originalwert zu verwenden.",
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"renderer\" verwendet. Spezielle Werte:\nLeer lassen, um den Originalwert zu verwenden\n\n{undefined}: gibt undefined zurück (#508)\n\n{false}: gibt den Wahrheitsert falsch zurück (#508)\n\n{empty}: gibt eine leere Zeichenkette zurück(#508)\n\n{disabled}: gibt null zurück (#508)\n\n{random vendor}: gibt einen zufälligen \"vendor\" aus der eingebauten Liste zurück (#493)\n\n{random renderer}: gibt einen zufälligen \"renderer\" aus der eingebauten Liste zurück (#493)\n\n<xxx|yyy|zzz>: wählt zufällig eine der Optionen xxx, yyy oder zzz aus (beliebige Anzahl von Optionen) (#493)",
"description": ""
},
"webGLUnmaskedVendor_title": {
@ -592,7 +660,7 @@
"description": ""
},
"webGLUnmaskedVendor_description": {
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"unmasked vendor\" verwendet. Leer lassen, um den Originalwert zu verwenden.",
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"unmasked vendor\" verwendet. Spezielle Werte:\nLeer lassen, um den Originalwert zu verwenden\n\n{undefined}: gibt undefined zurück (#508)\n\n{false}: gibt den Wahrheitsert falsch zurück (#508)\n\n{empty}: gibt eine leere Zeichenkette zurück(#508)\n\n{disabled}: gibt null zurück (#508)\n\n{random vendor}: gibt einen zufälligen \"vendor\" aus der eingebauten Liste zurück (#493)\n\n{random renderer}: gibt einen zufälligen \"renderer\" aus der eingebauten Liste zurück (#493)\n\n<xxx|yyy|zzz>: wählt zufällig eine der Optionen xxx, yyy oder zzz aus (beliebige Anzahl von Optionen) (#493)",
"description": ""
},
"webGLUnmaskedRenderer_title": {
@ -600,7 +668,7 @@
"description": ""
},
"webGLUnmaskedRenderer_description": {
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"unmasked renderer\" verwendet. Leer lassen, um den Originalwert zu verwenden.",
"message": "Dieser Wert wird in der webGL-Funktion \"getParameter\" für \"unmasked renderer\" verwendet. Spezielle Werte:\nLeer lassen, um den Originalwert zu verwenden\n\n{undefined}: gibt undefined zurück (#508)\n\n{false}: gibt den Wahrheitsert falsch zurück (#508)\n\n{empty}: gibt eine leere Zeichenkette zurück(#508)\n\n{disabled}: gibt null zurück (#508)\n\n{random vendor}: gibt einen zufälligen \"vendor\" aus der eingebauten Liste zurück (#493)\n\n{random renderer}: gibt einen zufälligen \"renderer\" aus der eingebauten Liste zurück (#493)\n\n<xxx|yyy|zzz>: wählt zufällig eine der Optionen xxx, yyy oder zzz aus (beliebige Anzahl von Optionen) (#493)",
"description": ""
},
"useCanvasCache_title": {
@ -671,6 +739,14 @@
"message": "DOMRect-Auslese vorgetäuscht auf {url}",
"description": ""
},
"fakedSVGReadout": {
"message": "SVG-Auslese vorgetäuscht auf {url}",
"description": ""
},
"fakedTextMetricsReadout": {
"message": "TextMetrics-Auslese vorgetäuscht auf {url}",
"description": ""
},
"fakedNavigatorReadout": {
"message": "Navigator-Auslese vorgetäuscht auf {url}",
"description": ""
@ -763,6 +839,10 @@
"message": "Was soll erlaubt werden?",
"description": ""
},
"selectWhitelistType": {
"message": "Wie soll erlaubt werden?",
"description": ""
},
"whitelistOnlyAPI": {
"message": "Erlaube nur die {api}",
"description": ""
@ -1107,6 +1187,30 @@
"message": "Ein Bruchteil eines Pixels kann durch CSS kontrolliert werden. Eigenschaften eines DOMRect, die multipliziert mit diesem Faktor eine ganze Zahl ergeben, dürfen nicht verändert werden um eine Detektion zu verhindern.",
"description": ""
},
"protectSVG_title": {
"message": "SVG-API beschützen",
"description": ""
},
"protectSVG_description": {
"message": "Dies schützt vor Fingerprinting, das SVGs verwendet.",
"description": ""
},
"protectSVG_urlSpecific": {
"message": "Um bestimmte Seiten von diesem Schutz auszuschließen, klicken Sie auf den schwarzen Pfeil um das Menü zu öffnen, fügen Sie die gewünschte Domain oder URL mit einem Klick auf \"+\" hinzu und entfernen Sie das zugehörige Häkchen.",
"description": ""
},
"protectTextMetrics_title": {
"message": "TextMetrics-API beschützen",
"description": ""
},
"protectTextMetrics_description": {
"message": "Beschützt vor dem \"measureText()\" Fingerprint. Dieser kann verwendet werden um die DOMRect-Werte zu überprüfen.",
"description": ""
},
"protectTextMetrics_urlSpecific": {
"message": "Um bestimmte Seiten von diesem Schutz auszuschließen, klicken Sie auf den schwarzen Pfeil um das Menü zu öffnen, fügen Sie die gewünschte Domain oder URL mit einem Klick auf \"+\" hinzu und entfernen Sie das zugehörige Häkchen.",
"description": ""
},
"protectNavigator_title": {
"message": "Navigator-API beschützen",
"description": ""
@ -1355,6 +1459,10 @@
"message": "Einstellungen",
"description": ""
},
"browserAction_faq": {
"message": "FAQ",
"description": ""
},
"browserAction_test": {
"message": "Testen",
"description": ""
@ -1415,6 +1523,10 @@
"message": "Alle Funktionen der {api} sind deaktiviert, aber der Schutz ist eingeschaltet.",
"description": ""
},
"sanitation_error.disabledSomeFeatures": {
"message": "Einige Funktionen der {api} sind deaktiviert. Dies sollte nur zu Testzwecken passieren oder wenn Sie genau wissen, was diese Funktionen tun.",
"description": ""
},
"sanitation_resolution.disableMainFlag": {
"message": "Hauptschalter deaktivieren",
"description": ""
@ -1448,7 +1560,7 @@
"description": ""
},
"sanitation_resolution.switchToNonPersistentRng": {
"message": "wechsle zu \"nicht persistent\"",
"message": "wechsle zu \"nichtpersistent\"",
"description": ""
},
"sanitation_error.fakeEverythingInCanvas": {
@ -1491,6 +1603,10 @@
"message": "CanvasBlocker Erlaubnisse ansehen",
"description": ""
},
"whitelist_inspection_description": {
"message": "Anzeige des API-Schutzes für eine bestimmte Webseite. Wenn man das Häkchen bei einer API entfernt, wird diese für die ausgewählte Webseite nicht mehr beschützt.",
"description": ""
},
"whitelist_all_apis": {
"message": "Alle APIs",
"description": ""
@ -1544,11 +1660,11 @@
"description": ""
},
"preset_recaptcha_title": {
"message": "reCAPTCHA Ausnahme",
"message": "reCAPTCHA-Ausnahme",
"description": ""
},
"preset_recaptcha_description": {
"message": "Der window-API-Schutz macht reCAPTCHA unbenutzbar. Diese Voreinstellung erlaubt die Benutzung der window.name-API in eingebetteten Seiten. Dadurch funktioniert es wieder.",
"message": "Der Window-API-Schutz macht reCAPTCHA unbenutzbar. Diese Voreinstellung erlaubt die Benutzung der window.name-API in eingebetteten Seiten, wodurch es wieder funktioniert.",
"description": ""
}
}

View File

@ -24,6 +24,14 @@
"message": "\n \u00B7 {api}",
"description": ""
},
"browserAction_status_on": {
"message": "CanvasBlocker on",
"description": ""
},
"browserAction_status_off": {
"message": "CanvasBlocker off",
"description": ""
},
"more": {
"message": "more",
@ -92,11 +100,20 @@
"message": "You have privacy.resistFingerprinting enabled. This slightly changes the behaviour of CanvasBlocker. See further information {link:here:https://github.com/kkapsner/CanvasBlocker/issues/158} and {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"description": ""
},
"settingsNotice.dom.webAudio.enabled": {
"message": "You have dom.webAudio.enabled disabled. This makes you more trackable as very few people do this.",
"description": ""
},
"openInTab": {
"message": "Open in separate tab",
"description": ""
},
"labelForDefaultOption": {
"message": " (default)",
"description": ""
},
"group_general": {
"message": "General",
"description": ""
@ -154,6 +171,14 @@
"message": "DOMRect API",
"description": ""
},
"section_SVG-api": {
"message": "SVG API",
"description": ""
},
"section_TextMetrics-api": {
"message": "TextMetrics API",
"description": ""
},
"section_Navigator-api": {
"message": "Navigator API",
"description": ""
@ -181,6 +206,28 @@
"description": ""
},
"disruptSessionOnUpdate_title": {
"message": "Disrupt session on update",
"description": ""
},
"disruptSessionOnUpdate_description": {
"message": "If set to true the extension will update as soon as the update is available. This might break some tabs that are currently open.",
"description": ""
},
"reloadExtension_title": {
"message": "Reload extension",
"description": ""
},
"reloadExtension_description": {
"message": "Perform a pending update.",
"description": ""
},
"reloadExtension_label": {
"message": "Reload",
"description": ""
},
"hideSetting": {
"message": "Click here to hide this setting.",
"description": ""
@ -279,6 +326,30 @@
"message": "Do you want to allow DOMRect API readout?",
"description": ""
},
"askForSVGPermission": {
"message": "Do you want to allow the SVG API?",
"description": ""
},
"askForSVGInputPermission": {
"message": "Do you want to allow SVG API input?",
"description": ""
},
"askForSVGReadoutPermission": {
"message": "Do you want to allow SVG API readout?",
"description": ""
},
"askForTextMetricsPermission": {
"message": "Do you want to allow the TextMetrics API?",
"description": ""
},
"askForTextMetricsInputPermission": {
"message": "Do you want to allow TextMetrics API input?",
"description": ""
},
"askForTextMetricsReadoutPermission": {
"message": "Do you want to allow TextMetrics API readout?",
"description": ""
},
"askForNavigatorPermission": {
"message": "Do you want to allow the navigator API?",
"description": ""
@ -308,7 +379,7 @@
"description": ""
},
"askOnlyOnce_description": {
"message": "When CanvasBlocker's block mode is set to 'ask permission' or 'ask permission for readout API', a confirm message will appear every time a page tries to access the API or readout API. This setting tries to display the confirm message only once for each page regardless of how many times the page tries to access the API. Nevertheless, multiple confirm messages may still be displayed on some pages.\n\nNo: asking every time\n\nIndividual: each API-type (context, input, readout) has to be confirmed separately\n\ncombined: all API-types get confirmed together",
"message": "When CanvasBlocker's block mode is set to 'ask permission' or 'ask permission for readout API', a confirm message will appear every time a page tries to access the API or readout API. This setting tries to display the confirm message only once for each page regardless of how many times the page tries to access the API. Nevertheless, multiple confirm messages may still be displayed on some pages.\n\nNo: asking every time\n\nIndividual: each API type (context, input, readout) has to be confirmed separately\n\nCombined: all API types get confirmed together",
"description": ""
},
"askOnlyOnce_options.no": {
@ -429,7 +500,7 @@
},
"urlSettings_title": {
"message": "Site specific values",
"message": "Site-specific values",
"description": ""
},
"urlSettings_description": {
@ -461,7 +532,7 @@
},
"rng_description": {
"message": "none (completely white): a completely white image is returned. The option \"Fake the alpha channel\" should be activated with this. CAUTION: Do not use this with the \"fake at input\" mode.\n\nnon persistent: the random numbers will be determined freshly for each faking action.\n\nconstant: within one web page a color will always be faked to the same color.\n\npersistent: the random number will only be determined once for every domain.",
"message": "none (completely white): a completely white image is returned. The option \"Fake the alpha channel\" should be activated with this. CAUTION: Do not use this with the \"fake at input\" mode.\n\nnonpersistent: the random numbers will be determined freshly for each faking action. Keep in mind that many API protections have caches in place to prevent detection.\n\nconstant: variation of nonpersistent. But when altering canvas data same colored pixels also share the same color afterwards.\n\npersistent: the random number will only be determined once for every domain.",
"description": ""
},
"rng_options.persistent": {
@ -473,7 +544,7 @@
"description": ""
},
"rng_options.nonPersistent": {
"message": "non persistent",
"message": "nonpersistent",
"description": ""
},
"rng_options.white": {
@ -606,7 +677,7 @@
"description": ""
},
"webGLVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLRenderer_title": {
@ -614,7 +685,7 @@
"description": ""
},
"webGLRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedVendor_title": {
@ -622,7 +693,7 @@
"description": ""
},
"webGLUnmaskedVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedRenderer_title": {
@ -630,7 +701,7 @@
"description": ""
},
"webGLUnmaskedRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
@ -705,6 +776,14 @@
"message": "Faked DOMRect readout on {url}",
"description": ""
},
"fakedSVGReadout": {
"message": "Faked SVG readout on {url}",
"description": ""
},
"fakedTextMetricsReadout": {
"message": "Faked TextMetrics readout on {url}",
"description": ""
},
"fakedNavigatorReadout": {
"message": "Faked navigator readout on {url}",
"description": ""
@ -799,6 +878,10 @@
"message": "What is the scope of the whitelisting?",
"description": ""
},
"selectWhitelistType": {
"message": "What is the type of the whitelisting?",
"description": ""
},
"whitelistOnlyAPI": {
"message": "Whitelist only the {api}",
"description": ""
@ -1154,6 +1237,32 @@
"description": ""
},
"protectSVG_title": {
"message": "Protect SVG API",
"description": ""
},
"protectSVG_description": {
"message": "This protects against fingerprinting using SVGs.",
"description": ""
},
"protectSVG_urlSpecific": {
"message": "To exclude specific websites from this protection, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"description": ""
},
"protectTextMetrics_title": {
"message": "Protect TextMetrics API",
"description": ""
},
"protectTextMetrics_description": {
"message": "This protects against the \"measureText()\" fingerprinting which can be used to cross validate DOMRect values.",
"description": ""
},
"protectTextMetrics_urlSpecific": {
"message": "To exclude specific websites from this protection, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"description": ""
},
"protectNavigator_title": {
"message": "Protect navigator API",
"description": ""
@ -1415,6 +1524,10 @@
"message": "Settings",
"description": ""
},
"browserAction_faq": {
"message": "FAQ",
"description": ""
},
"browserAction_test": {
"message": "Test",
"description": ""
@ -1476,6 +1589,10 @@
"message": "All features of {api} are disabled but the protection is enabled.",
"description": ""
},
"sanitation_error.disabledSomeFeatures": {
"message": "Some features of {api} are disabled. This should only be done for testing or if you really know what the features are doing.",
"description": ""
},
"sanitation_resolution.disableMainFlag": {
"message": "disable main flag",
"description": ""
@ -1509,7 +1626,7 @@
"description": ""
},
"sanitation_resolution.switchToNonPersistentRng": {
"message": "switch to \"non persistent\" rng",
"message": "switch to \"nonpersistent\" rng",
"description": ""
},
"sanitation_error.fakeEverythingInCanvas": {
@ -1553,6 +1670,10 @@
"message": "CanvasBlocker whitelist inspection",
"description": ""
},
"whitelist_inspection_description": {
"message": "Shows which API protections are active for a given site. If you remove a checkmark for an API this API will be not protected for the selected site.",
"description": ""
},
"whitelist_all_apis": {
"message": "All APIs",
"description": ""

View File

@ -23,6 +23,14 @@
"message": "\n · {api}",
"description": ""
},
"browserAction_status_on": {
"message": "CanvasBlocker activado",
"description": ""
},
"browserAction_status_off": {
"message": "CanvasBlocker desactivado",
"description": ""
},
"more": {
"message": "más",
"description": ""
@ -40,15 +48,15 @@
"description": ""
},
"ok": {
"message": "OK",
"message": "Aceptar",
"description": ""
},
"apply": {
"message": "Apply",
"message": "Aplicar",
"description": ""
},
"cancel": {
"message": "Cancel",
"message": "Cancelar",
"description": ""
},
"input": {
@ -76,7 +84,7 @@
"description": ""
},
"updateNotice": {
"message": "Se ha actualizado CanvasBlocker. Si quiere poder acceder a está página más adelante y no la tiene en los marcadores, añádala.",
"message": "Se ha actualizado CanvasBlocker. Si quieres poder acceder a está página más adelante y no la tienes en los marcadores, añádela.",
"description": ""
},
"dontShowOptionsOnUpdate": {
@ -84,23 +92,31 @@
"description": ""
},
"resistFingerprintingNotice": {
"message": "You have privacy.resistFingerprinting enabled. This slightly changes the behaviour of CanvasBlocker. See further information {link:here:https://github.com/kkapsner/CanvasBlocker/issues/158} and {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"message": "Tienes habilitado privacy.resistFingerprinting. Esto cambia ligeramente el comportamiento de CanvasBlocker. Más información {link:aquí:https://github.com/kkapsner/CanvasBlocker/issues/158} y {link:aquí:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"description": ""
},
"settingsNotice.dom.webAudio.enabled": {
"message": "Tiene dom.webAudio.enabled desactivado. Esto le hace más rastreable ya que muy poca gente lo hace.",
"description": ""
},
"openInTab": {
"message": "Abrir en una pestaña separada",
"description": ""
},
"labelForDefaultOption": {
"message": " (default)",
"description": ""
},
"group_general": {
"message": "General",
"description": ""
},
"group_APIs": {
"message": "APIs",
"message": "API",
"description": ""
},
"group_misc": {
"message": "Misc",
"message": "Varios",
"description": ""
},
"section_asking": {
@ -120,7 +136,7 @@
"description": ""
},
"section_misc": {
"message": "Miscelánea",
"message": "Varios",
"description": ""
},
"section_settings": {
@ -136,7 +152,7 @@
"description": ""
},
"section_history-api": {
"message": "API de history",
"message": "API history",
"description": ""
},
"section_window-api": {
@ -147,12 +163,20 @@
"message": "API de DOMRect",
"description": ""
},
"section_SVG-api": {
"message": "SVG API",
"description": ""
},
"section_TextMetrics-api": {
"message": "API TextMetrics",
"description": ""
},
"section_Navigator-api": {
"message": "API de navigator",
"message": "API navigator",
"description": ""
},
"section_Screen-api": {
"message": "Screen API",
"message": "API pantalla",
"description": ""
},
"displayAdvancedSettings_title": {
@ -171,6 +195,26 @@
"message": "Muestra las descripciones de las opciones.",
"description": ""
},
"disruptSessionOnUpdate_title": {
"message": "Interrumpir sesión al actualizar",
"description": ""
},
"disruptSessionOnUpdate_description": {
"message": "Si se establece en true la extensión se actualizará tan pronto como la actualización esté disponible. Esto podría romper algunas pestañas que están actualmente abiertas.",
"description": ""
},
"reloadExtension_title": {
"message": "Recargar extensión",
"description": ""
},
"reloadExtension_description": {
"message": "Realizar una actualización pendiente.",
"description": ""
},
"reloadExtension_label": {
"message": "Recargar",
"description": ""
},
"hideSetting": {
"message": "Haga clic aquí para ocultar esta opción.",
"description": ""
@ -267,6 +311,30 @@
"message": "¿Quiere permitir la lectura para la API de DOMRect?",
"description": ""
},
"askForSVGPermission": {
"message": "¿Quiere permitir la API SVG?",
"description": ""
},
"askForSVGInputPermission": {
"message": "¿Quieres permitir la entrada de la API SVG?",
"description": ""
},
"askForSVGReadoutPermission": {
"message": "¿Quieres permitir la lectura de la API SVG?",
"description": ""
},
"askForTextMetricsPermission": {
"message": "¿Quiere permitir la API TextMetrics?",
"description": ""
},
"askForTextMetricsInputPermission": {
"message": "¿Quiere permitir la entrada de la API de TextMetrics?",
"description": ""
},
"askForTextMetricsReadoutPermission": {
"message": "¿Quiere permitir la lectura de la API de TextMetrics?",
"description": ""
},
"askForNavigatorPermission": {
"message": "¿Quiere permitir la API de navigator?",
"description": ""
@ -280,15 +348,15 @@
"description": ""
},
"askForScreenPermission": {
"message": "Do you want to allow the screen API?",
"message": "¿Quiere permitir la API de pantalla?",
"description": ""
},
"askForScreenInputPermission": {
"message": "Do you want to allow screen API input?",
"message": "¿Quiere permitir la entrada de la API de pantalla?",
"description": ""
},
"askForScreenReadoutPermission": {
"message": "Do you want to allow screen API readout?",
"message": "¿Quiere permitir la lectura de la API de pantalla?",
"description": ""
},
"askOnlyOnce_title": {
@ -440,7 +508,7 @@
"description": ""
},
"rng_description": {
"message": "ninguno (totalmente blanco): se devuelve una imagen totalmente blanca. La opción «Falsear el canal alfa» debe activarse junto a esta. PRECAUCIÓN: no usar con el modo «falsear a la entrada».\nno persistente: los números aleatorios se vuelven a calcular para cada acción de falseado.\nconstante: en una página web, un color se falsea siempre por el mismo color.\npersistente: el número aleatorio solo se calcula una vez por cada dominio.",
"message": "none (completely white): a completely white image is returned. The option \"Fake the alpha channel\" should be activated with this. CAUTION: Do not use this with the \"fake at input\" mode.\n\nnonpersistent: the random numbers will be determined freshly for each faking action. Keep in mind that many API protections have caches in place to prevent detection.\n\nconstant: variation of nonpersistent. But when altering canvas data same colored pixels also share the same color afterwards.\n\npersistent: the random number will only be determined once for every domain.",
"description": ""
},
"rng_options.persistent": {
@ -528,11 +596,11 @@
"description": ""
},
"clearPersistentRndForContainer_label": {
"message": "Clear container",
"message": "Limpiar contenedor",
"description": ""
},
"clearPersistentRndForContainer_title": {
"message": "Select container",
"message": "Seleccionar contenedor",
"description": ""
},
"sharePersistentRndBetweenDomains_title": {
@ -572,35 +640,35 @@
"description": ""
},
"webGLVendor_title": {
"message": "Reported webGL vendor",
"message": "Proveedor webGL reportado",
"description": ""
},
"webGLVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLRenderer_title": {
"message": "Reported webGL renderer",
"message": "Renderizador webGL reportado",
"description": ""
},
"webGLRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedVendor_title": {
"message": "Reported webGL unmasked vendor",
"message": "Proveedor webGL desenmascarado reportado",
"description": ""
},
"webGLUnmaskedVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedRenderer_title": {
"message": "Reported webGL unmasked renderer",
"message": "Renderizador webGL desenmascarado reportado",
"description": ""
},
"webGLUnmaskedRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"useCanvasCache_title": {
@ -671,12 +739,20 @@
"message": "Lectura de DOMRect falseada en {url}",
"description": ""
},
"fakedSVGReadout": {
"message": "Lectura SVG falseada en {url}",
"description": ""
},
"fakedTextMetricsReadout": {
"message": "Lectura de TextMetrics falseada en {url}",
"description": ""
},
"fakedNavigatorReadout": {
"message": "Lectura de navigator falseada en {url}",
"description": ""
},
"fakedScreenReadout": {
"message": "Faked screen readout on {url}",
"message": "Lectura de screen falseada en {url}",
"description": ""
},
"fakedInput": {
@ -700,7 +776,7 @@
"description": ""
},
"localFile": {
"message": "local file",
"message": "archivo local",
"description": ""
},
"ignorelistDomain": {
@ -763,6 +839,10 @@
"message": "¿Cuál es el alcance de la lista blanca?",
"description": ""
},
"selectWhitelistType": {
"message": "¿Cuál es el tipo de lista blanca?",
"description": ""
},
"whitelistOnlyAPI": {
"message": "Permitir solo {api}",
"description": ""
@ -940,7 +1020,7 @@
"description": ""
},
"protectAudio_title": {
"message": "Proteger la API de audio",
"message": "Proteger la API audio",
"description": ""
},
"protectAudio_description": {
@ -976,19 +1056,19 @@
"description": ""
},
"audioFakeRate_options.0.1%": {
"message": "0.1% de los valores",
"message": "0,1% de los valores",
"description": ""
},
"audioFakeRate_options.1%": {
"message": "1% de los valores",
"message": "1% de los valores",
"description": ""
},
"audioFakeRate_options.10%": {
"message": "10% de los valores",
"message": "10% de los valores",
"description": ""
},
"audioFakeRate_options.100%": {
"message": "100% de los valores",
"message": "100 % de los valores",
"description": ""
},
"audioNoiseLevel_title": {
@ -1028,7 +1108,7 @@
"description": ""
},
"useAudioCache_urlSpecific": {
"message": "Algunas páginas usan guiones para crear huellas digitales muy mal escritos que ralentizan Firefox. Para deshabilitar la caché para sitios web específicos, haga clic en la flecha negra para abrir el menú, añada el dominio o URL haciendo clic en «+» y desmarque la casilla.",
"message": "Algunas páginas usan scripts muy mal escritos con audio para crear huella digital que ralentizan Firefox. Para deshabilitar la caché para sitios web específicos, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"audioUseFixedIndices_title": {
@ -1060,7 +1140,7 @@
"description": ""
},
"protectWindow_title": {
"message": "Proteger la API de window",
"message": "Proteger la API window",
"description": ""
},
"protectWindow_description": {
@ -1068,35 +1148,35 @@
"description": ""
},
"protectWindow_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haga clic en la flecha negra para abrir el menú, añada el dominio o URL haciendo clic en «+» y desmarque la casilla.",
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"protectWindow_askReCaptchaException": {
"message": "La protección de la API de window rompe los reCAPTCHA. ¿Quiere añadir una excepción para eso?",
"message": "La protección de la API window rompe reCAPTCHA. ¿Quieres permitir la API window.name en las páginas integradas para que vuelva a funcionar?",
"description": ""
},
"allowWindowNameInFrames_title": {
"message": "Allow window.name in frames",
"message": "Permitir window.name en frames",
"description": ""
},
"allowWindowNameInFrames_description": {
"message": "The window.name API is not that dangerous in the context of embedded pages and it is used there for legitimate reasons (e.g. reCAPTCHA). This setting will allow these usages.",
"message": "La API window.name no es tan peligrosa en el contexto de las páginas incrustadas y se utiliza allí por razones legítimas (por ejemplo, reCAPTCHA). Esta configuración permitirá estos usos.",
"description": ""
},
"allowWindowNameInFrames_urlSpecific": {
"message": "To allow this only for specific websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and set its checkmark.",
"message": "Para permitir esto solo para sitios web específicos, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y marca la casilla.",
"description": ""
},
"protectDOMRect_title": {
"message": "Proteger la API de DOMRect",
"message": "Proteger la API DOMRect",
"description": ""
},
"protectDOMRect_description": {
"message": "Protege contra la huella digital mediante «getClientRects()» y varios métodos similares.",
"message": "Esto protege contra la huella digital mediante «getClientRects()» y varios métodos similares.",
"description": ""
},
"protectDOMRect_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haga clic en la flecha negra para abrir el menú, añada el dominio o URL haciendo clic en «+» y desmarque la casilla.",
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"domRectIntegerFactor_title": {
@ -1107,16 +1187,40 @@
"message": "Alguna fracción de un píxel puede ser controlada con CSS. Para prevenir la detección, los valores de un DOMRect que multiplicados por este factor sean números enteros no serán modificados.",
"description": ""
},
"protectSVG_title": {
"message": "Proteger API SVG",
"description": ""
},
"protectSVG_description": {
"message": "Esto protege contra la toma de huellas dactilares usando SVGs.",
"description": ""
},
"protectSVG_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haga clic en la flecha negra para abrir el menú, añada el dominio o la URL haciendo clic en \"+\" y quite su marca de verificación.",
"description": ""
},
"protectTextMetrics_title": {
"message": "Proteger la API TextMetrics",
"description": ""
},
"protectTextMetrics_description": {
"message": "Esto protege contra la huella digital mediante «measureText()» que se pueden usar para validar de forma cruzada los valores DOMRect.",
"description": ""
},
"protectTextMetrics_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"protectNavigator_title": {
"message": "Proteger la API de navigator",
"message": "Proteger la API navigator",
"description": ""
},
"protectNavigator_description": {
"message": "Esta página permite cambios en la API de navigator. Habilitar esta protección no cambia nada por defecto. Abra la configuración de navigator para especificar allí los cambios que desee.",
"message": "Esta página permite cambios en la API navigator. Habilitar esta protección no cambia nada por defecto. Abre la configuración de navigator para especificar allí los cambios que desees.",
"description": ""
},
"protectNavigator_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haga clic en la flecha negra para abrir el menú, añada el dominio o URL haciendo clic en «+» y desmarque la casila.",
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"openNavigatorSettings_title": {
@ -1136,7 +1240,7 @@
"description": ""
},
"navigatorSettings_description": {
"message": "En esta página puede cambiar la configuración de navigator. Si usa un preajuste, debe usar siempre uno para sistema operativo y otro para el navegador. Después de seleccionarlos, todavía puede hacer modificaciones.",
"message": "En esta página puedes cambiar la configuración de navigator. Si usas un preajuste, siempre debes usar uno para el sistema operativo y otro para el navegador. Después de seleccionarlos, todavía puede hacer modificaciones.",
"description": ""
},
"navigatorSettings_disclaimer": {
@ -1144,7 +1248,7 @@
"description": ""
},
"navigatorSettings_contextualIdentities": {
"message": "Settings for the container {select} are shown.",
"message": "Se muestra la configuración del contenedor {select}.",
"description": ""
},
"navigatorSettings_presetSection.os": {
@ -1160,43 +1264,43 @@
"description": ""
},
"navigatorSettings_reset": {
"message": "Reiniciar",
"message": "Restablecer",
"description": ""
},
"protectScreen_title": {
"message": "Protect screen API",
"message": "Proteger la API screen",
"description": ""
},
"protectScreen_description": {
"message": "This protects against fingerprinting attempts including the screen size.",
"message": "Esto protege contra los intentos de crear huella digital, incluido el tamaño de la pantalla.",
"description": ""
},
"protectScreen_urlSpecific": {
"message": "To exclude specific websites from this protection, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"screenSize_title": {
"message": "Screen size",
"message": "Tamaño de pantalla",
"description": ""
},
"screenSize_description": {
"message": "If this is set with a value \"...x...\" the specified dimensions will be reported as the screen size.",
"message": "Si se establece con un valor \"...x...\" las dimensiones especificadas serán reportadas como el tamaño de la pantalla.",
"description": ""
},
"screenSize_urlSpecific": {
"message": "To provide specific sizes for certain websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and enter the desired value.",
"message": "Para proporcionar tamaños específicos para ciertos sitios web, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» e ingresa el valor deseado.",
"description": ""
},
"fakeMinimalScreenSize_title": {
"message": "Fake minimal screen size",
"message": "Tamaño mínimo falso de la pantalla",
"description": ""
},
"fakeMinimalScreenSize_description": {
"message": "Use a minimal screen size from the following set that can fit the inner window dimensions. Screen sizes: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
"message": "Utilice un tamaño de pantalla mínimo del siguiente conjunto que pueda ajustarse a las dimensiones de la ventana interior. Tamaños de pantalla: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
"description": ""
},
"fakeMinimalScreenSize_urlSpecific": {
"message": "To exclude specific websites from the faking, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"message": "Para excluir sitios web específicos del falseado, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"theme_title": {
@ -1212,7 +1316,7 @@
"description": ""
},
"theme_options.default": {
"message": "por defecto",
"message": "predeterminado",
"description": ""
},
"theme_options.light": {
@ -1240,7 +1344,7 @@
"description": ""
},
"blockDataURLs_urlSpecific": {
"message": "Para excluir sitios web específicos de esta protección, haga clic en la flecha negra para abrir el menú, añada el dominio o URL haciendo clic en «+» y desmarque la casila.",
"message": "Para excluir sitios web específicos de esta protección, haz clic en la flecha negra para abrir el menú, añade el dominio o URL haciendo clic en «+» y desmarca la casilla.",
"description": ""
},
"showReleaseNotes_title": {
@ -1288,7 +1392,7 @@
"description": ""
},
"exportSettings_title": {
"message": "Exportar la configuración",
"message": "Exportar configuración",
"description": ""
},
"exportSettings_description": {
@ -1296,7 +1400,7 @@
"description": ""
},
"settingControlling_title": {
"message": "Setting controlling",
"message": "Control de configuración",
"description": ""
},
"settingControlling_description": {
@ -1312,15 +1416,15 @@
"description": ""
},
"openSettingPresets_title": {
"message": "Presets",
"message": "Preajustes",
"description": ""
},
"openSettingPresets_description": {
"message": "This opens the preset page that was shown upon installation. The presets are collections of setting values for some common use cases of CanvasBlocker.",
"message": "Esto abre la página de preajustes que se mostró en la instalación. Los preajustes son colecciones de valores de configuración para algunos casos de uso común de CanvasBlocker.",
"description": ""
},
"openSettingPresets_label": {
"message": "Open",
"message": "Abrir",
"description": ""
},
"inspectSettings_label": {
@ -1336,7 +1440,7 @@
"description": ""
},
"resetSettings_title": {
"message": "Reiniciar la configuración",
"message": "Restablecer configuración",
"description": ""
},
"resetSettings_description": {
@ -1344,7 +1448,7 @@
"description": ""
},
"resetSettings_label": {
"message": "Reiniciar",
"message": "Restablecer",
"description": ""
},
"resetSettings_confirm": {
@ -1355,6 +1459,10 @@
"message": "Configuración",
"description": ""
},
"browserAction_faq": {
"message": "Preguntas frecuentes",
"description": ""
},
"browserAction_test": {
"message": "Probar",
"description": ""
@ -1415,6 +1523,10 @@
"message": "Todas las opciones de {api} están deshabilitadas pero la protección está habilitada.",
"description": ""
},
"sanitation_error.disabledSomeFeatures": {
"message": "Algunas características de {api} están deshabilitadas. Esto sólo debe hacerse para probar o si realmente sabe lo que las características están haciendo.",
"description": ""
},
"sanitation_resolution.disableMainFlag": {
"message": "deshabilitar la opción principal",
"description": ""
@ -1480,75 +1592,79 @@
"description": ""
},
"sanitation_error.doNotSharePersistentRndBetweenDomains": {
"message": "No compartir la aleatoriedad persistente entre dominios porque hace al navegador 100% rastreable.",
"message": "No compartir la aleatoriedad persistente entre dominios porque hace al navegador 100 % rastreable.",
"description": ""
},
"sanitation_error.customScreenSize": {
"message": "Do not use a custom screen size as it makes the browser more trackable.",
"message": "No utilice un tamaño de pantalla personalizado, ya que hace que el navegador sea más rastreable.",
"description": ""
},
"whitelist_inspection_title": {
"message": "Inspección de la lista blanca de CanvasBlocker",
"description": ""
},
"whitelist_inspection_description": {
"message": "Muestra las protecciones de las API que están activas para un sitio determinado. Si eliminas una marca de verificación para una API, esta API no estará protegida para el sitio seleccionado.",
"description": ""
},
"whitelist_all_apis": {
"message": "Todas las API",
"description": ""
},
"presets": {
"message": "Presets",
"message": "Preajustes",
"description": ""
},
"presets_title": {
"message": "CanvasBlocker presets",
"message": "Preajustes de CanvasBlocker",
"description": ""
},
"presets_installNotice": {
"message": "{image:../icons/icon.svg}Thanks for installing CanvasBlocker. To adjust it to your needs you can apply some presets. For further customization you can open the {link:options:options.html} page. There you can also open this preset page later.",
"message": "{image:../icons/icon.svg}Gracias por instalar CanvasBlocker. Para ajustarlo a tus necesidades puedes aplicar algunos preajustes. Para una mayor personalización puedes abrir la página de {link:opciones:options.html}. Allí también puedes abrir esta página de preajustes más tarde.",
"description": ""
},
"presets_introduction": {
"message": "These are some setting presets to fit different people's needs. The values in brackets are the current state of the setting. You can apply multiple presets after each other but some settings might be overwritten by the later applied one.",
"message": "Estos son algunos preajustes de configuración para adaptarse a las necesidades de diferentes personas. Los valores entre paréntesis son el estado actual de la configuración. Puedes aplicar múltiples preajustes de configuración uno tras otro, pero alguna configuración puede ser sobrescrita por el que se aplique más tarde.",
"description": ""
},
"preset_default_title": {
"message": "Default settings",
"message": "Configuración predeterminada",
"description": ""
},
"preset_default_description": {
"message": "No special settings are applied.",
"message": "No se han aplicado ajustes especiales.",
"description": ""
},
"preset_convenience_title": {
"message": "Convenient settings",
"message": "Configuración cómoda",
"description": ""
},
"preset_convenience_description": {
"message": "Apply some settings to make the browsing experience as convenient as possible. This includes whitelisting some sites.",
"message": "Aplica algunas configuraciones para que la experiencia de navegación sea lo más cómoda posible. Esto incluye la lista blanca de algunos sitios.",
"description": ""
},
"preset_stealth_title": {
"message": "Stealth settings",
"message": "Ajustes de sigilo",
"description": ""
},
"preset_stealth_description": {
"message": "Configures CanvasBlocker to be hard to detect. This might lead to high CPU usage and might slow down the browser.",
"message": "Configura CanvasBlocker para que sea difícil de detectar. Esto puede llevar a un alto uso de la CPU y puede ralentizar el navegador.",
"description": ""
},
"preset_max_protection_title": {
"message": "Maximum protection",
"message": "Máxima protección",
"description": ""
},
"preset_max_protection_description": {
"message": "Maximizes the protection against fingerprint extraction. These settings will break some pages, might slow down the browser a little bit and might enable sites to detect that CanvasBlocker is used. After applying this preset you should consider applying the reCAPTCHA preset as well.",
"message": "Maximiza la protección contra la extracción de huella dagital. Esta configuración romperá algunas páginas, podría ralentizar un poco el navegador y podría permitir a los sitios detectar si utilizas CanvasBlocker. Después de aplicar este preajuste, deberías considerar aplicar también el preajuste reCAPTCHA.",
"description": ""
},
"preset_recaptcha_title": {
"message": "reCAPTCHA exception",
"message": "Excepción de reCAPTCHA",
"description": ""
},
"preset_recaptcha_description": {
"message": "Protecting the window API breaks reCAPTCHA. This preset allows the usage of the window.name API in embedded pages which will make it work again.",
"message": "La protección de la API window rompe reCAPTCHA. Este preajuste permite el uso de la API window.name en páginas integradas, lo que hará que vuelva a funcionar.",
"description": ""
}
}

File diff suppressed because it is too large Load Diff

1670
_locales/hi/messages.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1670
_locales/ja/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/ko/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/lt/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/nb/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/pl/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/pt/messages.json Normal file

File diff suppressed because it is too large Load Diff

1670
_locales/pt_BR/messages.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,15 +16,23 @@
"description": ""
},
"browserAction_title_whitelisted": {
"message": " (API, белый список для {url})",
"message": " (API внесены в белый список для {url})",
"description": ""
},
"browserAction_title_protectedAPIs": {
"message": "\n · {api}",
"description": ""
},
"browserAction_status_on": {
"message": "CanvasBlocker вкл",
"description": ""
},
"browserAction_status_off": {
"message": "CanvasBlocker выкл",
"description": ""
},
"more": {
"message": "еще",
"message": "подробнее",
"description": ""
},
"less": {
@ -32,7 +40,7 @@
"description": ""
},
"pleaseWait": {
"message": "Подождите...",
"message": "Пожалуйста, подождите...",
"description": ""
},
"search": {
@ -72,11 +80,11 @@
"description": ""
},
"installNotice": {
"message": "CanvasBlocker установлен. Если вы хотите иметь доступ к этой странице в будущем, добавьте ее в закладки.",
"message": "CanvasBlocker установлен. Если вы хотите иметь доступ к этой странице в будущем, пожалуйста добавьте ее в закладки.",
"description": ""
},
"updateNotice": {
"message": "CanvasBlocker обновлен. Если вы хотите иметь доступ к этой странице в будущем и еще не добавили ее в закладки, добавьте ее в закладки.",
"message": "CanvasBlocker обновлен. Если вы хотите иметь доступ к этой странице в будущем и еще не добавили ее в закладки, пожалуйста добавьте.",
"description": ""
},
"dontShowOptionsOnUpdate": {
@ -84,13 +92,21 @@
"description": ""
},
"resistFingerprintingNotice": {
"message": "You have privacy.resistFingerprinting enabled. This slightly changes the behaviour of CanvasBlocker. See further information {link:here:https://github.com/kkapsner/CanvasBlocker/issues/158} and {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"message": "Настройка privacy.resistFingerprinting включена. Это немного влияет на работу CanvasBlocker. Подробнее см. {link:here:https://github.com/kkapsner/CanvasBlocker/issues/158} и {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"description": ""
},
"settingsNotice.dom.webAudio.enabled": {
"message": "You have dom.webAudio.enabled disabled. This makes you more trackable as very few people do this.",
"description": ""
},
"openInTab": {
"message": "Открыть в отдельной вкладке",
"description": ""
},
"labelForDefaultOption": {
"message": " (default)",
"description": ""
},
"group_general": {
"message": "Основные",
"description": ""
@ -104,7 +120,7 @@
"description": ""
},
"section_asking": {
"message": "Asking (спрашивать)",
"message": "Запрашивать",
"description": ""
},
"section_faking": {
@ -147,6 +163,14 @@
"message": "DOMRect API",
"description": ""
},
"section_SVG-api": {
"message": "SVG API",
"description": ""
},
"section_TextMetrics-api": {
"message": "TextMetrics API",
"description": ""
},
"section_Navigator-api": {
"message": "Navigator API",
"description": ""
@ -171,6 +195,26 @@
"message": "Отображает описания настроек.",
"description": ""
},
"disruptSessionOnUpdate_title": {
"message": "Прервать сессию при обновлении",
"description": ""
},
"disruptSessionOnUpdate_description": {
"message": "Если включено, то расширение будет обновляться, как только обновление станет доступно. Это может поломать некоторые вкладки, которые в настоящее время открыты.",
"description": ""
},
"reloadExtension_title": {
"message": "Перезагрузить расширение",
"description": ""
},
"reloadExtension_description": {
"message": "Выполнить ожидающее обновление.",
"description": ""
},
"reloadExtension_label": {
"message": "Перезагрузить",
"description": ""
},
"hideSetting": {
"message": "Нажмите здесь, чтобы скрыть эту настройку.",
"description": ""
@ -180,7 +224,7 @@
"description": ""
},
"displayHiddenSettings_description": {
"message": "Активируйте, чтобы отобразить скрытые настройки.",
"message": "Активируйте для просмотра скрытых настроек.",
"description": ""
},
"askForInvisiblePermission": {
@ -212,7 +256,7 @@
"description": ""
},
"askForVisibleInputPermission": {
"message": "Вы хотите разрешить input(запись) красной рамки для <canvas>?",
"message": "Вы хотите разрешить input(ввод) красной рамки для <canvas>?",
"description": ""
},
"askForVisibleReadoutPermission": {
@ -224,7 +268,7 @@
"description": ""
},
"askForAudioInputPermission": {
"message": "Вы хотите разрешить audio API input(ввод)?",
"message": "Вы хотите разрешить audio API input(вход)?",
"description": ""
},
"askForAudioReadoutPermission": {
@ -232,7 +276,7 @@
"description": ""
},
"askForHistoryPermission": {
"message": "Вы хотите разрешить the history API?",
"message": "Вы хотите разрешить API истории?",
"description": ""
},
"askForHistoryInputPermission": {
@ -256,7 +300,7 @@
"description": ""
},
"askForDOMRectPermission": {
"message": "Вы хотите разрешить the DOMRect API?",
"message": "Вы хотите разрешить DOMRect API?",
"description": ""
},
"askForDOMRectInputPermission": {
@ -267,6 +311,30 @@
"message": "Вы хотите разрешить DOMRect API readout(считывание)?",
"description": ""
},
"askForSVGPermission": {
"message": "Разрешить SVG API?",
"description": ""
},
"askForSVGInputPermission": {
"message": "Вы хотите разрешить SVG API input(ввод)?",
"description": ""
},
"askForSVGReadoutPermission": {
"message": "Разрешить SVG API readout(считывание)?",
"description": ""
},
"askForTextMetricsPermission": {
"message": "Вы хотите разрешить TextMetrics API?",
"description": ""
},
"askForTextMetricsInputPermission": {
"message": "Вы хотите разрешить TextMetrics API (ввод)?",
"description": ""
},
"askForTextMetricsReadoutPermission": {
"message": "Вы хотите разрешить считывание TextMetrics API?",
"description": ""
},
"askForNavigatorPermission": {
"message": "Вы хотите разрешить navigator API?",
"description": ""
@ -296,7 +364,7 @@
"description": ""
},
"askOnlyOnce_description": {
"message": "Когда в CanvasBlocker в режиме блокировать и установлено значение «запрашивать разрешение» или «запрашивать разрешение для API для чтения(readout)», сообщение подтверждения будет появляться каждый раз, когда страница пытается получить доступ к API или readout(считывание) API. Этот параметр пытается отобразить сообщение подтверждения только один раз для каждой страницы независимо от того, сколько раз страница пытается получить доступ к API. Тем не менее, несколько сообщений с подтверждением все еще могут отображаться на некоторых страницах.\n\nНет: каждый раз спрашивать\n\nИндивидуальный: каждый тип API (context(контекст), input(ввод), readout(считывание)) должен быть определен отдельно\n\n Комбинированный: все типы API будут подтверждены вместе",
"message": "Когда режим блокировки установлен в значение «запрашивать разрешение» или «запрашивать разрешение для API для чтения(readout)», подтверждение будет запрашиваться всякий раз, когда веб-страница пытается получить доступ к API или readout(считывание) API. Этот параметр снижает количество подтверждений для каждой страницы до одного раза независимо от того, сколько раз такая страница получает доступ к API. На некоторых страницах однако могут несколько сообщений.\n\nНет: спрашивать каждый раз\n\nИндивидуально: требовать отдельного подтверждения для каждого типа API (контекст, ввод, считывание)\n\n Комбинировать: все типы API будут подтверждены вместе",
"description": ""
},
"askOnlyOnce_options.no": {
@ -332,7 +400,7 @@
"description": ""
},
"showCanvasWhileAsking_description": {
"message": "Показывать содержимое canvas, для которого запрашивается разрешение, если это возможно.",
"message": "По возможности показывать содержимое canvas, для которого запрашивается разрешение.",
"description": ""
},
"showCanvasWhileAsking_message": {
@ -340,11 +408,11 @@
"description": ""
},
"blackList_description": {
"message": "Домены или URL-адреса, где все API всегда должны быть заблокированы. Чтобы добавить несколько записей, разделите их запятыми.",
"message": "Всегда блокировать API с этих доменов и URL-адресов. Записи в списке разделяются запятой.",
"description": ""
},
"blackList_title": {
"message": "Черный список",
"message": "Запрещенный список",
"description": ""
},
"blockMode_description": {
@ -388,31 +456,31 @@
"description": ""
},
"protectedCanvasPart_description": {
"message": "nothing: no features of the canvas API are protected.\n\nreadout: the readout features of the canvas API are protected.\n\ninput: the input features of the canvas API are protected. With blocking mode \"fake\" the drawn pixels get modified slightly when displaying text. This makes the detection of the add-on harder but is less secure. With WebGL canvases the behaviour is identical to \"readout\".\n\neverything: both the readout and input features are protected. It's not recommended to use this with \"fake\" block mode as it increases the probability to be detected.",
"message": "ничего: никакие функции API холста не защищены.\n\nсчитывание: функции считывания содержимого холста защищены.\n\nввод: функции ввода API холста защищены. В режиме блокировки \"подделывание\" немного изменяются пиксели при выводе текста. Это затрудняет обнаружение этого расширения, но является менее безопасным. Для холстов WebGL поведение идентично режиму \"Считывание\".\n\nвсё: защищены и функции считывания, и функции ввода. Не рекомендуется использовать этот режим в сочетании с режимом блокировки \"подделывание\", так как увеличивается вероятность обнаружения.",
"description": ""
},
"protectedCanvasPart_urlSpecific": {
"message": "To protect individual parts for specific websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and select the desired part.",
"message": "Чтобы установить защищаемые области для конкретных сайтов, нажмите на черную стрелку, чтобы открыть меню, добавьте домен или URL, нажав на \"+\", и выберите желаемую область.",
"description": ""
},
"protectedCanvasPart_options.nothing": {
"message": "nothing",
"message": "ничего",
"description": ""
},
"protectedCanvasPart_options.input": {
"message": "input",
"message": "ввод",
"description": ""
},
"protectedCanvasPart_options.readout": {
"message": "readout",
"message": "считывание",
"description": ""
},
"protectedCanvasPart_options.everything": {
"message": "everything",
"message": "всё",
"description": ""
},
"urlSettings_title": {
"message": "Сайты с конкретными значениями",
"message": "Значения для конкретного сайта",
"description": ""
},
"urlSettings_description": {
@ -432,7 +500,7 @@
"description": ""
},
"maxFakeSize_description": {
"message": "<canvas> с большей площадью, чем это число не будут подделаны. (Введите ноль, чтобы отключить.) Это параметр для производительности, который может предотвратить зависания браузера и должен быть настроен на вычислительную мощность устройства.\nВНИМАНИЕ: это снижает безопасность дополнения, поэтому настоятельно рекомендуется не устанавливать это значение ниже 1 000 000.",
"message": "<canvas> с большей площадью, чем это число не будут подделаны. (Введите ноль, чтобы отключить.) Этот параметр для производительности, который может предотвратить зависания браузера и должен быть настроен на вычислительную мощность устройства.\nВНИМАНИЕ: это снижает безопасность дополнения, поэтому настоятельно рекомендуется не устанавливать это значение ниже 1 000 000.",
"description": ""
},
"maxFakeSize_title": {
@ -440,7 +508,7 @@
"description": ""
},
"rng_description": {
"message": "отсутствут (полностью белый): возвращается полностью белое изображение. При этом должна быть активирована опция \"подделать альфа-канал\". ВНИМАНИЕ: не используйте это с режимом \"подделать для input(ввод)\".\n\nнепостоянный: случайные значения будут определяться заново для каждого действия подделки.\n\nконстантный: в пределах одной веб-страницы цвет всегда будет подделан на тот же цвет.\n\nпостоянный: случайное число будет определено только один раз для каждого домена.",
"message": "нет (белый цвет): возвращается полностью белое изображение. Должна быть включена опция \"подделывать альфа-канал\". ВНИМАНИЕ: Не используйте вместе с режимом \"подделка ввода(input)\".\n\nнепостоянный: для каждой подделки случайные числа будут генерироваться заново. Имейте ввиду, что большинство функций защиты API хранят кэш для предотвращения обнаружения.\n\nконстантный: вариация непостоянного. Только при изменении данных в <canvas> сохраняется цвет изменённых пикселей и доступен в дальнейшем.\n\nпостоянный: для каждого домена случайное число генерируется единожды.",
"description": ""
},
"rng_options.persistent": {
@ -464,7 +532,7 @@
"description": ""
},
"persistentRndStorage_title": {
"message": "Постоянное хранение",
"message": "Постоянное хранилище",
"description": ""
},
"persistentRndStorage_description": {
@ -476,11 +544,11 @@
"description": ""
},
"storePersistentRnd_description": {
"message": "Сохранять данные для постоянного генератора случайных чисел. В противном случае он сбрасываются при завершении работы браузера.",
"message": "Сохранять данные для постоянного генератора случайных чисел. В противном случае они сбрасываются при завершении работы браузера.",
"description": ""
},
"persistentRndClearInterval_title": {
"message": "Интервал отчистки постоянных данных",
"message": "Интервал очистки постоянных данных",
"description": ""
},
"persistentRndClearInterval_description": {
@ -508,7 +576,7 @@
"description": ""
},
"persistentRndClearIntervalUnit_options.months": {
"message": "месяцы",
"message": "месяцев",
"description": ""
},
"persistentRndClearIntervalUnit_options.years": {
@ -528,23 +596,23 @@
"description": ""
},
"clearPersistentRndForContainer_label": {
"message": "Clear container",
"message": "Очистить контейнер",
"description": ""
},
"clearPersistentRndForContainer_title": {
"message": "Select container",
"message": "Выбрать контейнер",
"description": ""
},
"sharePersistentRndBetweenDomains_title": {
"message": "Share persistent randomness between domains",
"message": "Распределение постоянной случайности между доменами",
"description": ""
},
"sharePersistentRndBetweenDomains_description": {
"message": "CAUTION: this setting makes the browser 100% trackable and is therefore a threat to your privacy.",
"message": "ВНИМАНИЕ: эта настройка делает браузер на 100% уязвимым для отслеживания, а значит, является угрозой для вашей приватности.",
"description": ""
},
"sharePersistentRndBetweenDomains_confirmMessage": {
"message": "Are you really sure you want to share the persistent randomness between domains?\nCAUTION: this makes the browser 100% trackable and is therefore a threat to your privacy.",
"message": "Вы уверены, что действительно хотите использовать общие случайные данные для всех доменов?\nВНИМАНИЕ: эта сделает браузер на 100% уязвимым для отслеживания, а значит, является угрозой для вашей приватности.",
"description": ""
},
"ignoreFrequentColors_title": {
@ -572,35 +640,35 @@
"description": ""
},
"webGLVendor_title": {
"message": "Reported webGL vendor",
"message": "Сообщать производителя webGL",
"description": ""
},
"webGLVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLRenderer_title": {
"message": "Reported webGL renderer",
"message": "Сообщать растеризатор webGL",
"description": ""
},
"webGLRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedVendor_title": {
"message": "Reported webGL unmasked vendor",
"message": "Сообщать производителя webGL (без маскировки)",
"description": ""
},
"webGLUnmaskedVendor_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedRenderer_title": {
"message": "Reported webGL unmasked renderer",
"message": "Сообщать растеризатор webGL (без маскировки)",
"description": ""
},
"webGLUnmaskedRenderer_description": {
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Leave empty to use the original value.",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"useCanvasCache_title": {
@ -671,12 +739,20 @@
"message": "Подделан DOMRect readout(чтение) на {url}",
"description": ""
},
"fakedSVGReadout": {
"message": "Подделан SVG readout(чтение) на {url}",
"description": ""
},
"fakedTextMetricsReadout": {
"message": "Фальшивое считывание TextMetrics на {url}",
"description": ""
},
"fakedNavigatorReadout": {
"message": "Faked navigator readout on {url}",
"message": "Подделывать считывание навигатора для {url}",
"description": ""
},
"fakedScreenReadout": {
"message": "Faked screen readout on {url}",
"message": "Подделывать считывание экрана для {url}",
"description": ""
},
"fakedInput": {
@ -763,6 +839,10 @@
"message": "Какова сфера действия белого списка?",
"description": ""
},
"selectWhitelistType": {
"message": "What is the type of the whitelisting?",
"description": ""
},
"whitelistOnlyAPI": {
"message": "Добавить в белый список только для {api}",
"description": ""
@ -904,7 +984,7 @@
"description": ""
},
"inspectWhitelist": {
"message": "inspect whitelist",
"message": "проверить белый список",
"description": ""
},
"sessionWhiteList_title": {
@ -1056,7 +1136,7 @@
"description": ""
},
"historyLengthThreshold_urlSpecific": {
"message": "To change this value for specific websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and set a different value.",
"message": "Чтобы изменить значение для конкретных сайтов, нажмите на черную стрелку, чтобы открыть меню, добавьте домен или URL, нажав на \"+\", и выберите другое значение.",
"description": ""
},
"protectWindow_title": {
@ -1076,15 +1156,15 @@
"description": ""
},
"allowWindowNameInFrames_title": {
"message": "Allow window.name in frames",
"message": "Разрешить window.name во фреймах",
"description": ""
},
"allowWindowNameInFrames_description": {
"message": "The window.name API is not that dangerous in the context of embedded pages and it is used there for legitimate reasons (e.g. reCAPTCHA). This setting will allow these usages.",
"message": "В контексте фрейма window.name не является столь опасным и используется для других целей (например reCAPTCHA). Эта настройка разрешает такое использование.",
"description": ""
},
"allowWindowNameInFrames_urlSpecific": {
"message": "To allow this only for specific websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and set its checkmark.",
"message": "Чтобы разрешить это только для конкретных сайтов, нажмите на черную стрелку, чтобы открыть меню, добавьте домен или URL, нажав на \"+\", и отметьте флажок.",
"description": ""
},
"protectDOMRect_title": {
@ -1092,7 +1172,7 @@
"description": ""
},
"protectDOMRect_description": {
"message": "Это защищает от снятия отпечатков \"getClientRects()\" и нескольких подобных методов.",
"message": "Защищает от снятия отпечатка \"getClientRects()\" и нескольких подобных методов.",
"description": ""
},
"protectDOMRect_urlSpecific": {
@ -1107,20 +1187,44 @@
"message": "С помощью CSS можно управлять некоторой частью пикселя. Чтобы предотвратить обнаружение, значения DOMRect, которые умножаются на этот коэффициент, целые числа не будут изменены.",
"description": ""
},
"protectSVG_title": {
"message": "Защищать SVG API",
"description": ""
},
"protectSVG_description": {
"message": "Защищает от снятия отпечатка через SVG.",
"description": ""
},
"protectSVG_urlSpecific": {
"message": "Чтобы отключить защиту для конкретных сайтов, нажмите на чёрную стрелку открытия меню, добавьте домен или URL нажатием на \"+\" и снимите с него флажок.",
"description": ""
},
"protectTextMetrics_title": {
"message": "Защита API TextMetrics",
"description": ""
},
"protectTextMetrics_description": {
"message": "Защищает от снятия отпечатка \"measureText()\", который может быть использован для перекрестной проверки значений DOMRect.",
"description": ""
},
"protectTextMetrics_urlSpecific": {
"message": "Чтобы исключить определенные сайты из этой защиты, нажмите на черную стрелку, чтобы открыть меню, добавьте домен или URL, нажав на \"+\" и снимите галочку.",
"description": ""
},
"protectNavigator_title": {
"message": "Protect navigator API",
"message": "Защита API навигатора",
"description": ""
},
"protectNavigator_description": {
"message": "This page allows for changes in the navigator API. Enabling this protection does not change anything by default. Open the navigator settings to specify the changes you want to have there.",
"message": "Эта страница позволяет вносить изменения в API навигатора. Включение защиты по умолчанию ничего не меняет. Откройте настройки навигатора и укажите там желаемые изменения.",
"description": ""
},
"protectNavigator_urlSpecific": {
"message": "To exclude specific websites from this protection, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"message": "Чтобы исключить конкретные сайты из этой защиты, нажмите на черную стрелку, чтобы открыть меню, добавьте домен или URL, нажав на \"+\", и снимите флажок.",
"description": ""
},
"openNavigatorSettings_title": {
"message": "Navigator settings",
"message": "Настройки навигатора",
"description": ""
},
"openNavigatorSettings_description": {
@ -1128,47 +1232,47 @@
"description": ""
},
"openNavigatorSettings_label": {
"message": "Open",
"message": "Открыть",
"description": ""
},
"navigatorSettings_title": {
"message": "CanvasBlocker navigator settings",
"message": "CanvasBlocker: Настройки навигатора",
"description": ""
},
"navigatorSettings_description": {
"message": "On this page you can set the navigator settings. If using a preset you should always use an operating system and browser preset. After selecting these you can still make modifications.",
"message": "На этой странице можно настроить параметры навигатора. При использовании предустановок всегда следует использовать предустановки операционной системы и браузера. После их выбора Вы все еще можете вносить изменения.",
"description": ""
},
"navigatorSettings_disclaimer": {
"message": "CAUTION: the actual browser in use cannot be faked entirely as there is a multitude of ways to detect it. E.g. feature tests and browser specific rendering of HTML elements will always leak.",
"message": "ВНИМАНИЕ: используемый браузер не может быть полностью подделан, так как существует множество способов его обнаружения. Например, функциональные тесты и рендеринг HTML-элементов, специфичный для браузера, всегда будут утечки.",
"description": ""
},
"navigatorSettings_contextualIdentities": {
"message": "Settings for the container {select} are shown.",
"message": "Показаны настройки контейнера {select}.",
"description": ""
},
"navigatorSettings_presetSection.os": {
"message": "Operating system presets",
"message": "Предустановки операционной системы",
"description": ""
},
"navigatorSettings_presetSection.browser": {
"message": "Browser presets",
"message": "Предустановки браузера",
"description": ""
},
"navigatorSettings_values": {
"message": "Navigator values",
"message": "Значения навигатора",
"description": ""
},
"navigatorSettings_reset": {
"message": "Reset",
"message": "Сброс",
"description": ""
},
"protectScreen_title": {
"message": "Protect screen API",
"message": "Защитить API экрана",
"description": ""
},
"protectScreen_description": {
"message": "Это защищает от попыток снятия цифровых отпечатков, включая размер экрана.",
"message": "Защищает от попыток снятия отпечатка на основе таких характеристик, как размер экрана.",
"description": ""
},
"protectScreen_urlSpecific": {
@ -1188,15 +1292,15 @@
"description": ""
},
"fakeMinimalScreenSize_title": {
"message": "Fake minimal screen size",
"message": "Поддельный минимальный размер экрана",
"description": ""
},
"fakeMinimalScreenSize_description": {
"message": "Use a minimal screen size from the following set that can fit the inner window dimensions. Screen sizes: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
"message": "Минимальный размер экрана из следующего набора, который может соответствовать размерам внутреннего окна. Размеры экрана: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
"description": ""
},
"fakeMinimalScreenSize_urlSpecific": {
"message": "To exclude specific websites from the faking, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
"message": "Чтобы исключить конкретные веб-сайты из числа подделываемых, нажмите на черную стрелку, чтобы открыть меню, добавить домен или URL-адрес, нажав на кнопку \"+\" и убрать галочку.",
"description": ""
},
"theme_title": {
@ -1204,7 +1308,7 @@
"description": ""
},
"theme_description": {
"message": "The automatic theme switches to dark if the system uses a dark theme (requires Firefox >= 67)",
"message": "Автоматически тема переключается на темную, если система использует темную тему (требуется Firefox >= 67)",
"description": ""
},
"theme_options.auto": {
@ -1316,7 +1420,7 @@
"description": ""
},
"openSettingPresets_description": {
"message": "This opens the preset page that was shown upon installation. The presets are collections of setting values for some common use cases of CanvasBlocker.",
"message": "Откроется страница предварительной настройки, которая была показана при установке. Заготовки представляют собой наборы значений настроек для некоторых распространенных случаев использования CanvasBlocker.",
"description": ""
},
"openSettingPresets_label": {
@ -1355,6 +1459,10 @@
"message": "Настройки",
"description": ""
},
"browserAction_faq": {
"message": "ЧАВО",
"description": ""
},
"browserAction_test": {
"message": "Проверка",
"description": ""
@ -1400,7 +1508,7 @@
"description": ""
},
"sanitation_ruleset.privacy": {
"message": "Privacy",
"message": "Политика конфиденциальности",
"description": ""
},
"sanitation_error.unnecessaryURLValue": {
@ -1408,13 +1516,17 @@
"description": ""
},
"sanitation_resolution.removeURLValue": {
"message": "remove URL value",
"message": "удалить URL значение",
"description": ""
},
"sanitation_error.disabledFeatures": {
"message": "Все функции {api} отключены, но защита включена.",
"description": ""
},
"sanitation_error.disabledSomeFeatures": {
"message": "Некоторые функции {api} отключены. Это должно быть сделано только для тестирования или если вы действительно знаете, что делаете.",
"description": ""
},
"sanitation_resolution.disableMainFlag": {
"message": "отключить главный флаг",
"description": ""
@ -1428,7 +1540,7 @@
"description": ""
},
"sanitation_resolution.switchToFake": {
"message": "switch to \"fake\"",
"message": "переключиться на \"fake\"",
"description": ""
},
"sanitation_error.blockModeVsProtection": {
@ -1444,7 +1556,7 @@
"description": ""
},
"sanitation_resolution.switchToProtectReadout": {
"message": "switch to protect readout",
"message": "переключатель для защиты считывания",
"description": ""
},
"sanitation_resolution.switchToNonPersistentRng": {
@ -1452,11 +1564,11 @@
"description": ""
},
"sanitation_error.fakeEverythingInCanvas": {
"message": "Do not use protect \"{protectedCanvasPart}\" in blocking mode \"{blockMode}\".",
"message": "Не используйте защиту \"{protectedCanvasPart}\" в режиме блокировки \"{blockMode}\".",
"description": ""
},
"sanitation_resolution.switchToProtectInput": {
"message": "switch to protect input",
"message": "переключатель для защиты ввода",
"description": ""
},
"sanitation_error.valueTooLow": {
@ -1480,75 +1592,79 @@
"description": ""
},
"sanitation_error.doNotSharePersistentRndBetweenDomains": {
"message": "Do not share persistent randomness between domains because this makes the browser 100% trackable.",
"message": "Не распространяйте постоянную случайность между доменами, потому что это делает браузер на 100% отслеживаемым.",
"description": ""
},
"sanitation_error.customScreenSize": {
"message": "Do not use a custom screen size as it makes the browser more trackable.",
"message": "Не используйте пользовательский размер экрана, так как это делает браузер более отслеживаемым.",
"description": ""
},
"whitelist_inspection_title": {
"message": "CanvasBlocker whitelist inspection",
"message": "Проверка белого списка CanvasBlocker",
"description": ""
},
"whitelist_inspection_description": {
"message": "Показывает какие типы защиты API активны для данного сайта. Если вы удалите флажок для какого-либо API, этот API не будет защищен для выбранного сайта.",
"description": ""
},
"whitelist_all_apis": {
"message": "All APIs",
"message": "Все API",
"description": ""
},
"presets": {
"message": "Presets",
"message": "Преднастройки",
"description": ""
},
"presets_title": {
"message": "CanvasBlocker presets",
"message": "Пресеты CanvasBlocker",
"description": ""
},
"presets_installNotice": {
"message": "{image:../icons/icon.svg}Thanks for installing CanvasBlocker. To adjust it to your needs you can apply some presets. For further customization you can open the {link:options:options.html} page. There you can also open this preset page later.",
"message": "{image:../icons/icon.svg}Спасибо за установку CanvasBlocker. Чтобы настроить его в соответствии с вашими потребностями, вы можете применить некоторые пресеты. Для дальнейшей настройки вы можете открыть {link:options:options.html} страницу. Так же вы можете открыть эту страницу позже.",
"description": ""
},
"presets_introduction": {
"message": "These are some setting presets to fit different people's needs. The values in brackets are the current state of the setting. You can apply multiple presets after each other but some settings might be overwritten by the later applied one.",
"message": "Это некоторые пресеты, которые соответствуют потребностям разных людей. Значения в скобках являются текущим состоянием настройки. Вы можете применять несколько пресетов друг за другом, но некоторые настройки могут быть перезаписаны позднее.",
"description": ""
},
"preset_default_title": {
"message": "Default settings",
"message": "Стандартные параметры",
"description": ""
},
"preset_default_description": {
"message": "No special settings are applied.",
"message": "Никаких специальных настроек не применяется.",
"description": ""
},
"preset_convenience_title": {
"message": "Convenient settings",
"message": "Удобные настройки",
"description": ""
},
"preset_convenience_description": {
"message": "Apply some settings to make the browsing experience as convenient as possible. This includes whitelisting some sites.",
"message": "Примените некоторые настройки, чтобы сделать работу браузера максимально удобной. Это включает в себя белый список некоторых сайтов.",
"description": ""
},
"preset_stealth_title": {
"message": "Stealth settings",
"message": "Настройки скрытности",
"description": ""
},
"preset_stealth_description": {
"message": "Configures CanvasBlocker to be hard to detect. This might lead to high CPU usage and might slow down the browser.",
"message": "Настраивает CanvasBlocker так, чтобы его было трудно обнаружить. Это может привести к высокой загрузке процессора и замедлению работы браузера.",
"description": ""
},
"preset_max_protection_title": {
"message": "Maximum protection",
"message": "Максимальная защита",
"description": ""
},
"preset_max_protection_description": {
"message": "Maximizes the protection against fingerprint extraction. These settings will break some pages, might slow down the browser a little bit and might enable sites to detect that CanvasBlocker is used. After applying this preset you should consider applying the reCAPTCHA preset as well.",
"message": "Максимизирует защиту от снятия отпечатков. Эти настройки сломают некоторые веб-страницы, могут немного замедлить работу браузера и могут позволить сайтам обнаружить, что используется CanvasBlocker. После применения этой предустановки следует подумать о применении также и предустановки reCAPTCHA.",
"description": ""
},
"preset_recaptcha_title": {
"message": "reCAPTCHA exception",
"message": "Исключение reCAPTCHA",
"description": ""
},
"preset_recaptcha_description": {
"message": "Protecting the window API breaks reCAPTCHA. This preset allows the usage of the window.name API in embedded pages which will make it work again.",
"message": "Защита window API нарушает reCAPTCHA. Вы хотите добавить исключение для него.",
"description": ""
}
}

View File

@ -4,7 +4,7 @@
"description": ""
},
"addon_description": {
"message": "改变修改 <canvas> 的 JS-API 来预防画布Canvas指纹跟踪。",
"message": "改变某些 JavaScript API 来阻止跟踪。",
"description": ""
},
"browserAction_title_default": {
@ -23,6 +23,14 @@
"message": "\n · {api}",
"description": ""
},
"browserAction_status_on": {
"message": "CanvasBlocker 开启",
"description": ""
},
"browserAction_status_off": {
"message": "CanvasBlocker 关闭",
"description": ""
},
"more": {
"message": "更多",
"description": ""
@ -56,7 +64,7 @@
"description": ""
},
"readout": {
"message": "读",
"message": "读",
"description": ""
},
"options": {
@ -68,7 +76,7 @@
"description": ""
},
"optionsIntroduction": {
"message": "此页面提供选项来更改 CanvasBlocker 扩展的设置。",
"message": "在此页面上,您可以调整 CanvasBlocker 的设置。",
"description": ""
},
"installNotice": {
@ -84,13 +92,21 @@
"description": ""
},
"resistFingerprintingNotice": {
"message": "You have privacy.resistFingerprinting enabled. This slightly changes the behaviour of CanvasBlocker. See further information {link:here:https://github.com/kkapsner/CanvasBlocker/issues/158} and {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}.",
"message": "您启用了 privacy.resistFingerprinting这明显改变了 CanvasBlocker 的行为。更多信息请参阅 {link:https://github.com/kkapsner/CanvasBlocker/issues/158} 和 {link:here:https://github.com/ghacksuserjs/ghacks-user.js/issues/767}。",
"description": ""
},
"settingsNotice.dom.webAudio.enabled": {
"message": "您禁用了 dom.webAudio这使您更容易被追踪因为很少人这样做。",
"description": ""
},
"openInTab": {
"message": "在新标签页中打开",
"description": ""
},
"labelForDefaultOption": {
"message": " (default)",
"description": ""
},
"group_general": {
"message": "一般",
"description": ""
@ -147,12 +163,20 @@
"message": "DOMRect API",
"description": ""
},
"section_SVG-api": {
"message": "SVG API",
"description": ""
},
"section_TextMetrics-api": {
"message": "TextMetrics API",
"description": ""
},
"section_Navigator-api": {
"message": "Navigator API",
"description": ""
},
"section_Screen-api": {
"message": "Screen API",
"message": "屏幕 API",
"description": ""
},
"displayAdvancedSettings_title": {
@ -160,7 +184,7 @@
"description": ""
},
"displayAdvancedSettings_description": {
"message": "显示额外设置",
"message": "显示附加设置。",
"description": ""
},
"displayDescriptions_title": {
@ -171,12 +195,32 @@
"message": "显示设置的说明。",
"description": ""
},
"disruptSessionOnUpdate_title": {
"message": "更新时中断会话",
"description": ""
},
"disruptSessionOnUpdate_description": {
"message": "如果设置为 true扩展将在可用更新后尽快更新。这可能会破坏当前打开的某些标签。",
"description": ""
},
"reloadExtension_title": {
"message": "重新加载扩展",
"description": ""
},
"reloadExtension_description": {
"message": "进行一个待处理的更新。",
"description": ""
},
"reloadExtension_label": {
"message": "重新载入",
"description": ""
},
"hideSetting": {
"message": "点击这里以隐藏该设置。",
"description": ""
},
"displayHiddenSettings_title": {
"message": "显示隐藏设置",
"message": "显示隐藏设置",
"description": ""
},
"displayHiddenSettings_description": {
@ -192,7 +236,7 @@
"description": ""
},
"askForInvisibleReadoutPermission": {
"message": "是否允许不可见的 <canvas> 读",
"message": "是否允许不可见的 <canvas> 读",
"description": ""
},
"askForPermission": {
@ -204,7 +248,7 @@
"description": ""
},
"askForReadoutPermission": {
"message": "是否允许 <canvas> 读",
"message": "是否允许 <canvas> 读",
"description": ""
},
"askForVisiblePermission": {
@ -212,11 +256,11 @@
"description": ""
},
"askForVisibleInputPermission": {
"message": "是否允许输入红边框的 <canvas>?",
"message": "是否允许红边框的 <canvas> 输入?",
"description": ""
},
"askForVisibleReadoutPermission": {
"message": "是否允许红边框的 <canvas> 读?",
"message": "是否允许红边框的 <canvas> 读?",
"description": ""
},
"askForAudioPermission": {
@ -228,7 +272,7 @@
"description": ""
},
"askForAudioReadoutPermission": {
"message": "是否允许音频 API 读",
"message": "是否允许音频 API 读",
"description": ""
},
"askForHistoryPermission": {
@ -240,7 +284,7 @@
"description": ""
},
"askForHistoryReadoutPermission": {
"message": "是否允许历史 API 读",
"message": "是否允许历史 API 读",
"description": ""
},
"askForWindowPermission": {
@ -252,7 +296,7 @@
"description": ""
},
"askForWindowReadoutPermission": {
"message": "是否允许 window API 读",
"message": "是否允许 window API 读",
"description": ""
},
"askForDOMRectPermission": {
@ -264,7 +308,31 @@
"description": ""
},
"askForDOMRectReadoutPermission": {
"message": "是否允许 DOMRect API 读数?",
"message": "是否允许 window API 读取?",
"description": ""
},
"askForSVGPermission": {
"message": "是否允许SVG API",
"description": ""
},
"askForSVGInputPermission": {
"message": "是否允许 SVG API 输入?",
"description": ""
},
"askForSVGReadoutPermission": {
"message": "是否允许 SVG API 读取?",
"description": ""
},
"askForTextMetricsPermission": {
"message": "是否允许 TextMetrics API",
"description": ""
},
"askForTextMetricsInputPermission": {
"message": "是否允许 TextMetrics API 输入?",
"description": ""
},
"askForTextMetricsReadoutPermission": {
"message": "是否允许 TextMetrics API 读取?",
"description": ""
},
"askForNavigatorPermission": {
@ -276,11 +344,11 @@
"description": ""
},
"askForNavigatorReadoutPermission": {
"message": "是否允许 Navigator API 读",
"message": "是否允许 Navigator API 读",
"description": ""
},
"askForScreenPermission": {
"message": "您想要放行Screen API吗?",
"message": "您想要允许 Screen API 吗?",
"description": ""
},
"askForScreenInputPermission": {
@ -288,7 +356,7 @@
"description": ""
},
"askForScreenReadoutPermission": {
"message": "是否允许 Screen API 读",
"message": "是否允许 Screen API 读",
"description": ""
},
"askOnlyOnce_title": {
@ -296,7 +364,7 @@
"description": ""
},
"askOnlyOnce_description": {
"message": "当 Canvas Blocker 的阻止模式设为“询问权限”或“询问读 API 权限”时,每次页面尝试访问有关 API 或取 API 时将出现一个对话框。此设置是为了尽量只对每个页面的若干次尝试只显示一个对话框。不过,在某些页面上,本扩展仍可能显示多条确认信息。\n否询问每个尝试\n分别每种 API 尝试(上下文、输入、取数)分别确认\n组合:一次确认所有种类的 API",
"message": "当 Canvas Blocker 的阻止模式设为“询问权限”或“询问读 API 权限”时,每次页面尝试访问有关 API 或取 API 时将出现一个对话框。此设置是为了当每个页面进行若干次尝试时尽量只显示一个对话框。不过,在某些页面上,本扩展仍可能显示多条确认信息。\n否询问每个尝试\n分别每种 API 尝试(上下文、输入、取取)分别确认\n全部:一次确认所有种类的 API",
"description": ""
},
"askOnlyOnce_options.no": {
@ -308,7 +376,7 @@
"description": ""
},
"askOnlyOnce_options.combined": {
"message": "组合",
"message": "全部",
"description": ""
},
"askDenyMode_title": {
@ -332,7 +400,7 @@
"description": ""
},
"showCanvasWhileAsking_description": {
"message": "询问权限时尽可能显示 Canvas 内容。",
"message": "尽可能显示被请求权限的 Canvas 内容。",
"description": ""
},
"showCanvasWhileAsking_message": {
@ -364,7 +432,7 @@
"description": ""
},
"blockMode_options.ask": {
"message": "询问权限",
"message": "请求权限",
"description": ""
},
"blockMode_options.blockEverything": {
@ -376,7 +444,7 @@
"description": ""
},
"blockMode_options.fake": {
"message": "伪",
"message": "伪",
"description": ""
},
"blockMode_title": {
@ -388,7 +456,7 @@
"description": ""
},
"protectedCanvasPart_description": {
"message": "无保护:不保护任何 Canvas API。\n读保护:保护 Canvas API 当中的读数功能。\n写保护:保护 Canvas API 当中的输入功能。当拦截模式为”伪造“时,展示文本时绘制的像素会有轻微调整。这使得 CanvasBlocker 检测更难但是同时降低安全性。WebGL 当中读写等效。\n全保护:同时保护 Canvas API 当中的读取与输入功能。由于会增加被检测到的概率,因此不建议与同时使用”伪造“模式。",
"message": "无保护:不保护任何 Canvas API。\n读取:保护 Canvas API 当中的读取功能。\n输入:保护 Canvas API 当中的输入功能。当拦截模式为”伪造“时,展示文本时绘制的像素会有轻微调整。这使得 CanvasBlocker 更难被检测但是同时降低安全性。WebGL 中读写等效。\n全部:同时保护 Canvas API 当中的读取与输入功能。由于会增加被检测到的概率,因此不建议与”伪造“模式同时使用。",
"description": ""
},
"protectedCanvasPart_urlSpecific": {
@ -404,7 +472,7 @@
"description": ""
},
"protectedCanvasPart_options.readout": {
"message": "读",
"message": "读",
"description": ""
},
"protectedCanvasPart_options.everything": {
@ -440,7 +508,7 @@
"description": ""
},
"rng_description": {
"message": "无(全白):返回一个完全是白色的图像。使用此选项时,“伪造 alpha 通道”选项应该激活配合。注意:使用“输入时伪造”模式时不应使用。\n非持久化每个伪造行动都确定新的随机数。\n不变同一个网页中一个颜色总被伪造成另一个相同的颜色。\n持久化对每个域名只确定一次随机数。",
"message": "none (completely white): a completely white image is returned. The option \"Fake the alpha channel\" should be activated with this. CAUTION: Do not use this with the \"fake at input\" mode.\n\nnonpersistent: the random numbers will be determined freshly for each faking action. Keep in mind that many API protections have caches in place to prevent detection.\n\nconstant: variation of nonpersistent. But when altering canvas data same colored pixels also share the same color afterwards.\n\npersistent: the random number will only be determined once for every domain.",
"description": ""
},
"rng_options.persistent": {
@ -476,7 +544,7 @@
"description": ""
},
"storePersistentRnd_description": {
"message": "如果没有存储随机数生成器的持久化数据,相应数据在浏览器关闭时丢弃。",
"message": "如果没有存储随机数生成器的持久化数据,相应数据在浏览器关闭时丢弃。",
"description": ""
},
"persistentRndClearInterval_title": {
@ -536,7 +604,7 @@
"description": ""
},
"sharePersistentRndBetweenDomains_title": {
"message": "在域名间享持久的随机性",
"message": "在域名间享持久的随机性",
"description": ""
},
"sharePersistentRndBetweenDomains_description": {
@ -544,7 +612,7 @@
"description": ""
},
"sharePersistentRndBetweenDomains_confirmMessage": {
"message": "您确定要在域名间享持久的随机性?\n注意这个设置会使浏览器 100% 会被追踪,并因此威胁你的隐私。",
"message": "您确定要在域名间享持久的随机性?\n注意这个设置会使浏览器 100% 会被追踪,并因此威胁你的隐私。",
"description": ""
},
"ignoreFrequentColors_title": {
@ -572,11 +640,11 @@
"description": ""
},
"webGLVendor_title": {
"message": "WebGL 渲染器商",
"message": "WebGL 渲染器提供商",
"description": ""
},
"webGLVendor_description": {
"message": "在 WebGL 函数 getParameter 当中报告的渲染器的值。留空即为原始值。",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLRenderer_title": {
@ -584,23 +652,23 @@
"description": ""
},
"webGLRenderer_description": {
"message": "在 WebGL 函数 getParameter 当中报告的渲染器的值。留空即为原始值。",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedVendor_title": {
"message": "WebGL 中未隐藏的渲染器商",
"message": "WebGL 中未隐藏的渲染器提供商",
"description": ""
},
"webGLUnmaskedVendor_description": {
"message": "在 WebGL 函数 getParameter 当中报告的渲染器的值。留空即为原始值。",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"webGLUnmaskedRenderer_title": {
"message": "WebGL 中未隐藏的渲染器厂商",
"message": "已报告的 WebGL 中未隐藏的渲染器提供商",
"description": ""
},
"webGLUnmaskedRenderer_description": {
"message": "在 WebGL 函数 getParameter 当中报告的渲染器的值。留空即为原始值。",
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
"description": ""
},
"useCanvasCache_title": {
@ -608,7 +676,7 @@
"description": ""
},
"useCanvasCache_description": {
"message": "启用 Canvas 缓存。这可以预防检测并在小画布Canvas被数次读取时增加性能,但对于大画布则降低性能。",
"message": "启用 Canvas 缓存。这可以防止检测并在小画布Canvas被多次读取时提高性能,但对于大画布则降低性能。",
"description": ""
},
"protectedAPIFeatures_title": {
@ -652,35 +720,43 @@
"description": ""
},
"fakedReadout": {
"message": "{url} 上的已伪造 Canvas 读数",
"message": "{url} 上的 Canvas 读数已伪造",
"description": ""
},
"fakedAudioReadout": {
"message": "{url} 上的已伪造音频取数",
"message": "{url} 上的音频读数已伪造",
"description": ""
},
"fakedHistoryReadout": {
"message": "{url} 上的已伪造历史读数",
"message": "{url} 上的历史读数已伪造",
"description": ""
},
"fakedWindowReadout": {
"message": "{url} 上的已伪造 window 读数",
"message": "{url} 上的窗口读数已伪造",
"description": ""
},
"fakedDOMRectReadout": {
"message": "{url} 上的 DOMRect 已伪造读数",
"message": "{url} 上的 DOMRect 读数已伪造",
"description": ""
},
"fakedSVGReadout": {
"message": "已伪造 {url} 上的 SVG 读取",
"description": ""
},
"fakedTextMetricsReadout": {
"message": "{url} 上的 TextMetrics 读数已伪造",
"description": ""
},
"fakedNavigatorReadout": {
"message": "{url} 上的 Navigator 已伪造读数",
"message": "{url} 上的 Navigator 读数已伪造",
"description": ""
},
"fakedScreenReadout": {
"message": "在 {url} 上伪造屏幕读数",
"message": "{url} 上的屏幕读数已伪造",
"description": ""
},
"fakedInput": {
"message": "{url} 上的画布输入已伪造",
"message": "已伪造 {url} 上的 canvas 输入",
"description": ""
},
"ignoreList_description": {
@ -696,7 +772,7 @@
"description": ""
},
"ignoredAPIs_description": {
"message": "没有用于所选 API 的提示。",
"message": "没有用于所选 API 的通知。",
"description": ""
},
"localFile": {
@ -763,6 +839,10 @@
"message": "白名单的范围是什么?",
"description": ""
},
"selectWhitelistType": {
"message": "白名单的类型是什么?",
"description": ""
},
"whitelistOnlyAPI": {
"message": "仅限 {api}",
"description": ""
@ -792,7 +872,7 @@
"description": ""
},
"showNotifications_description": {
"message": "阻止模式设为“伪造取出 API”时显示一个通知。",
"message": "当进行屏蔽或伪造时,在地址栏中显示通知图标。",
"description": ""
},
"showNotifications_urlSpecific": {
@ -880,7 +960,7 @@
"description": ""
},
"whiteList_description": {
"message": "应该阻止使用 <canvas> API 的域名或 URL。多项请使用英文逗号分隔。",
"message": "允许调用所有 API 的域名或 URL。多项请使用英文逗号分隔。",
"description": ""
},
"whitelist": {
@ -912,15 +992,15 @@
"description": ""
},
"sessionWhiteList_description": {
"message": "本次会话期间拦截 <canvas> API 使用的域名或 URL。多项请使用英文逗号分隔。",
"message": "本次会话期间允许调用所有 API 的域名或 URL。多项请使用英文逗号分隔。",
"description": ""
},
"whitelistDomainTemporarily": {
"message": "临时白名单域名",
"message": "临时域名白名单",
"description": ""
},
"whitelistURLTemporarily": {
"message": "临时白名单 URL",
"message": "临时 URL 白名单",
"description": ""
},
"storeNotificationData_title": {
@ -936,7 +1016,7 @@
"description": ""
},
"storeImageForInspection_description": {
"message": "开始存储已伪造的画布内容。\n注意这可能消耗大量内存",
"message": "启用存储已伪造画布的内容。\n注意这可能消耗大量内存",
"description": ""
},
"protectAudio_title": {
@ -944,7 +1024,7 @@
"description": ""
},
"protectAudio_description": {
"message": "如果同时音频API",
"message": "如果音频 API 也要保护",
"description": ""
},
"protectAudio_urlSpecific": {
@ -952,11 +1032,11 @@
"description": ""
},
"audioFakeRate_title": {
"message": "缓冲伪装的比例",
"message": "缓冲伪造率",
"description": ""
},
"audioFakeRate_description": {
"message": "每个读取请求应该伪多少值。",
"message": "每个读取请求应该伪多少值。",
"description": ""
},
"audioFakeRate_options.1": {
@ -1028,7 +1108,7 @@
"description": ""
},
"useAudioCache_urlSpecific": {
"message": "有些网页音频指纹脚本编写不良,导致拖慢 Firefox。如需针对特定网站禁用缓存请点击黑箭头打开菜单 点击“+”添加域名或URL并删除其复选标记。",
"message": "有些网页音频指纹脚本编写不良,导致拖慢 Firefox。如需针对特定网站禁用缓存请点击黑箭头打开菜单 点击“+”添加域名或URL并取消勾选。",
"description": ""
},
"audioUseFixedIndices_title": {
@ -1044,7 +1124,7 @@
"description": ""
},
"audioFixedIndices_description": {
"message": "以下为总是伪装的指数,使用逗号分隔。",
"message": "以下为总是伪装的指数。要添加多个项目,请用逗号分隔。",
"description": ""
},
"historyLengthThreshold_title": {
@ -1052,7 +1132,7 @@
"description": ""
},
"historyLengthThreshold_description": {
"message": "报告给网站的历史长度最大值。",
"message": "报告给网站的历史记录最大值。",
"description": ""
},
"historyLengthThreshold_urlSpecific": {
@ -1064,7 +1144,7 @@
"description": ""
},
"protectWindow_description": {
"message": "window.opener 和 window.name 将被保护。这会保护某些无用的网页。",
"message": "window.opener 和 window.name 将受到保护。这可能会使一些网页无法使用。",
"description": ""
},
"protectWindow_urlSpecific": {
@ -1072,7 +1152,7 @@
"description": ""
},
"protectWindow_askReCaptchaException": {
"message": "保护窗口 API 妨碍 reCAPTCHA。您是否添加例外",
"message": "保护窗口 API 妨碍 reCAPTCHA。您是否添加例外",
"description": ""
},
"allowWindowNameInFrames_title": {
@ -1080,7 +1160,7 @@
"description": ""
},
"allowWindowNameInFrames_description": {
"message": "在嵌入网页的上下文当中window.name API 并不是那么危险的,并且使用目的也是正当的(比如 reCAPTCHA。以下设置会允许这些。",
"message": "在嵌入网页的上下文当中window.name API 并不是那么危险的,并且使用目的也是正当的(比如 reCAPTCHA。以下设置会允许这些使用。",
"description": ""
},
"allowWindowNameInFrames_urlSpecific": {
@ -1092,7 +1172,7 @@
"description": ""
},
"protectDOMRect_description": {
"message": "这一保护反对 \"getClientRects()\" 指纹和一些类似的方法。",
"message": "这会阻止 “getClientRects()” 指纹和几种类似的方法。",
"description": ""
},
"protectDOMRect_urlSpecific": {
@ -1107,6 +1187,30 @@
"message": "像素的有些部分可以被 CSS 控制。为阻止检测,用这一整数系数增值的 DOMRect 的值将不被改变。",
"description": ""
},
"protectSVG_title": {
"message": "保护 SVG API",
"description": ""
},
"protectSVG_description": {
"message": "这阻止使用SVG生成指纹。",
"description": ""
},
"protectSVG_urlSpecific": {
"message": "如需排除特定网站,请点击黑箭头,然后单击 + 添加域名或 URL 并取消勾选。",
"description": ""
},
"protectTextMetrics_title": {
"message": "保护 TextMetrics API",
"description": ""
},
"protectTextMetrics_description": {
"message": "这保护了可用于验证 DOMRect 值的 “measureText()” 指纹。",
"description": ""
},
"protectTextMetrics_urlSpecific": {
"message": "如需排除特定网站,请点击黑箭头打开菜单, 点击 + 添加域名或 URL 并取消勾选。",
"description": ""
},
"protectNavigator_title": {
"message": "保护 Navigator API",
"description": ""
@ -1136,7 +1240,7 @@
"description": ""
},
"navigatorSettings_description": {
"message": "在本页你可以设置 Navigator 选项。若使用预置,你应该始终使用系统和浏览器预置。选择这些以后你仍可以做出修改。",
"message": "在本页你可以设置 Navigator 选项。若使用预设,你应该始终使用系统和浏览器预设。选择这些以后你仍可以做出修改。",
"description": ""
},
"navigatorSettings_disclaimer": {
@ -1144,15 +1248,15 @@
"description": ""
},
"navigatorSettings_contextualIdentities": {
"message": "Settings for the container {select} are shown.",
"message": "{select} 容器的设置已经显示。",
"description": ""
},
"navigatorSettings_presetSection.os": {
"message": "操作系统预",
"message": "操作系统预",
"description": ""
},
"navigatorSettings_presetSection.browser": {
"message": "浏览器预",
"message": "浏览器预",
"description": ""
},
"navigatorSettings_values": {
@ -1188,7 +1292,7 @@
"description": ""
},
"fakeMinimalScreenSize_title": {
"message": "伪装屏幕尺寸最小值",
"message": "伪造屏幕最小尺寸",
"description": ""
},
"fakeMinimalScreenSize_description": {
@ -1196,7 +1300,7 @@
"description": ""
},
"fakeMinimalScreenSize_urlSpecific": {
"message": "如需排除特定网站,请点击黑箭头打开菜单, 点击 + 添加域名或 URL 并删除其复选标记。",
"message": "如需排除特定网站,请点击黑箭头打开菜单, 点击 + 添加域名或 URL 并取消勾选。",
"description": ""
},
"theme_title": {
@ -1260,7 +1364,7 @@
"description": ""
},
"logLevel_description": {
"message": "此参数控制日志记录的详细程度。",
"message": "详细记录插件活动有助于找到错误的原因。这个参数控制记录的详细程度。\n\n日志可以在浏览器控制台(Ctrl+Shift+J) 和 Web 控制台(Ctrl+Shift+K) 中查看。",
"description": ""
},
"logLevel_options.0": {
@ -1316,7 +1420,7 @@
"description": ""
},
"openSettingPresets_description": {
"message": "这将打开安装时显示的预设页面。预设是 CanvasBlocker 设置的组合,用于一些通用情况。",
"message": "这将打开安装时显示的预设页面。预设是 CanvasBlocker 设置的组合,用于一些常见情况。",
"description": ""
},
"openSettingPresets_label": {
@ -1355,6 +1459,10 @@
"message": "设置",
"description": ""
},
"browserAction_faq": {
"message": "FAQ",
"description": ""
},
"browserAction_test": {
"message": "测试",
"description": ""
@ -1372,7 +1480,7 @@
"description": ""
},
"sanitation_description": {
"message": "本页面帮助查找 CanvasBlocker 中的错误配置同时对并不理想的设置给出建议。但是不建议盲目修正所有建议。",
"message": "本页面帮助查找 CanvasBlocker 中的错误配置,并同时对并不理想的设置给出建议。但是不建议盲目修正所有建议。",
"description": ""
},
"sanitation_nothingToComplain": {
@ -1415,6 +1523,10 @@
"message": "{api} 的所有特性都被禁用,但是启用了保护。",
"description": ""
},
"sanitation_error.disabledSomeFeatures": {
"message": "{api} 的一些特性被禁用。仅用于测试,或者您真的知道这些特性的用途。",
"description": ""
},
"sanitation_resolution.disableMainFlag": {
"message": "禁用主要 flag",
"description": ""
@ -1444,11 +1556,11 @@
"description": ""
},
"sanitation_resolution.switchToProtectReadout": {
"message": "切换到读保护",
"message": "切换到读保护",
"description": ""
},
"sanitation_resolution.switchToNonPersistentRng": {
"message": "切换到“非持久化”rng",
"message": "切换到“非持久化”随机数生成器",
"description": ""
},
"sanitation_error.fakeEverythingInCanvas": {
@ -1476,11 +1588,11 @@
"description": ""
},
"sanitation_error.storeImage": {
"message": "为检查存储图像产生大量的 RAM 足迹。",
"message": "存储要检查的图像产生大量的 RAM 指纹。",
"description": ""
},
"sanitation_error.doNotSharePersistentRndBetweenDomains": {
"message": "不要在域名间共享持久的随机性,因为这导致浏览器 100% 可以被追踪。",
"message": "不要在域名间共享持久的随机性,因为这导致浏览器 100% 可以被追踪。",
"description": ""
},
"sanitation_error.customScreenSize": {
@ -1491,6 +1603,10 @@
"message": "CanvasBlocker 白名单检查",
"description": ""
},
"whitelist_inspection_description": {
"message": "显示指定站点的 API 保护情况。 如果您取消一个 API 的勾选,此 API 将不会对选定的站点进行保护。",
"description": ""
},
"whitelist_all_apis": {
"message": "所有 API",
"description": ""
@ -1524,7 +1640,7 @@
"description": ""
},
"preset_convenience_description": {
"message": "以下设置会使浏览体验更加便捷。这会添加一些网站到白名单",
"message": "以下设置会使浏览体验更加便捷。这会添加一些网站到白名单",
"description": ""
},
"preset_stealth_title": {

1670
_locales/zh_TW/messages.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -19,4 +19,53 @@ div {
.action.search {
padding-left: calc(0.5em + 19px + 0.25em);
}
#headerActions {
display: grid;
grid-template-columns: 0.5fr 50px 0.5fr;
grid-template-rows: auto;
}
#addonStatus {
grid-row: 1 / 2;
grid-column: 2 / 3;
border: none;
display: block;
margin: 5px auto;
width: 40px;
min-width: 0;
height: 40px;
background: none;
background-position: 50%;
background-size: 100%;
cursor: pointer;
}
#addonStatus.unknown {
background-image: radial-gradient(black, rgba(0, 0, 0, 0), transparent);;
}
#addonStatus.off {
background-image: url(../icons/browserAction-CBoff.svg);
}
#addonStatus.on {
background-image: url(../icons/browserAction-CBon.svg);
}
#reload {
grid-row: 1 / 2;
grid-column: 3 / 4;
cursor: pointer;
height: 19px;
width: 19px;
align-self: center;
justify-self: left;
margin-left: 1em;
background-color: currentColor;
mask-size: 100%;
mask-image: url(../icons/browserAction-reload.svg);
}
#reload.hidden {
display: none;
}

View File

@ -7,14 +7,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="headerActions">
<button id="addonStatus" class="undefined"></button>
<div id="reload" class="hidden"></div>
</div>
<div id="actions" class="stackedInputs"></div>
<script src="../lib/require.js"></script>
<div id="version" class="versionDisplay"></div>
<script src="../lib/require.js"></script>
<script src="../lib/logging.js"></script>
<script src="../lib/extension.js"></script>
<script src="../lib/settingDefinitions.js"></script>
<script src="../lib/settingContainers.js"></script>
<script src="../lib/settings.js"></script>
<script src="../lib/theme.js"></script>
<script src="../lib/extension.js"></script>
<script src="../lib/settingDefinitions.js"></script>
<script src="../lib/settingContainers.js"></script>
<script src="../lib/settings.js"></script>
<script src="../lib/lists.js"></script>
<script src="../lib/theme.js"></script>
<script src="browserAction.js"></script>
</body>
</html>

View File

@ -7,48 +7,116 @@
const extension = require("../lib/extension");
const logging = require("../lib/logging");
const settings = require("../lib/settings");
const settingContainers = require("../lib/settingContainers");
const lists = require("../lib/lists");
require("../lib/theme").init();
logging.message("Opened browser action");
settings.onloaded(function(){
const actions = document.getElementById("actions");
browser.tabs.query({active: true, currentWindow: true}).then(async function([currentTab]){
function isWhitelisted(url){
if (!(url instanceof URL)){
url = new URL(url);
}
return lists.get("white").match(url) ||
settings.get("blockMode", url).startsWith("allow");
}
[
{
label: "settings",
icon: browser.extension.getURL("icons/pageAction-showOptions.svg"),
action: function(){
if (browser.runtime && browser.runtime.openOptionsPage){
browser.runtime.openOptionsPage();
}
else {
window.open(browser.extension.getURL("options/options.html"), "_blank");
}
const currentURL = new URL(currentTab.url);
const reloadButton = document.getElementById("reload");
reloadButton.addEventListener("click", async function(){
await browser.tabs.reload(currentTab.id, {bypassCache: true});
window.close();
});
const addonStatus = document.getElementById("addonStatus");
addonStatus.addEventListener("click", async function(){
reloadButton.classList.toggle("hidden");
if (isWhitelisted(currentURL)){
settingContainers.resetUrlValue("blockMode", currentURL);
if (settings.get("blockMode").startsWith("allow")){
settings.set("blockMode", "fake", currentURL.host);
}
},
{
label: "test",
advanced: true,
icon: browser.extension.getURL("icons/browserAction-test.svg"),
action: function(){
window.open("https://canvasblocker.kkapsner.de/test", "_blank");
if (settings.get("blockDataURLs")){
settingContainers.resetUrlValue("blockDataURLs", currentURL);
}
},
{
label: "review",
icon: browser.extension.getURL("icons/browserAction-review.svg"),
action: function(){
window.open("https://addons.mozilla.org/firefox/addon/canvasblocker/reviews/", "_blank");
const entries = lists.get("white").filter(e => e.match(currentURL)).map(e => e.value);
await Promise.all([
lists.removeFrom("white", entries),
lists.removeFrom("sessionWhite", entries)
]);
}
else {
settings.set("blockMode", "allowEverything", currentURL.hostname);
if (settings.get("blockDataURLs")){
settings.set("blockDataURLs", false, currentURL.hostname);
}
},
{
label: "reportIssue",
icon: browser.extension.getURL("icons/browserAction-reportIssue.svg"),
action: function(){
window.open("https://github.com/kkapsner/CanvasBlocker/issues", "_blank");
}
update();
});
function update(){
if (isWhitelisted(currentURL)){
addonStatus.className = "off";
addonStatus.title = extension.getTranslation("browserAction_status_off");
}
else {
addonStatus.className = "on";
addonStatus.title = extension.getTranslation("browserAction_status_on");
}
}
return settings.onloaded(update);
}).catch(function(){});
const actionDefinitions = [
{
label: "settings",
icon: extension.getURL("icons/pageAction-showOptions.svg"),
action: function(){
if (browser.runtime && browser.runtime.openOptionsPage){
browser.runtime.openOptionsPage();
}
},
].forEach(function(action){
else {
browser.tabs.create({url: extension.getURL("options/options.html")});
}
window.close();
}
},
{
label: "faq",
icon: extension.getURL("icons/browserAction-faq.svg"),
action: function(){
browser.tabs.create({url: "https://canvasblocker.kkapsner.de/faq/"});
window.close();
}
},
{
label: "test",
advanced: true,
icon: extension.getURL("icons/browserAction-test.svg"),
action: function(){
browser.tabs.create({url: "https://canvasblocker.kkapsner.de/test"});
window.close();
}
},
{
label: "review",
icon: extension.getURL("icons/browserAction-review.svg"),
action: function(){
browser.tabs.create({url: "https://addons.mozilla.org/firefox/addon/canvasblocker/reviews/"});
window.close();
}
},
{
label: "reportIssue",
icon: extension.getURL("icons/browserAction-reportIssue.svg"),
action: function(){
browser.tabs.create({url: "https://github.com/kkapsner/CanvasBlocker/issues"});
window.close();
}
},
];
settings.onloaded(async function(){
const actions = document.getElementById("actions");
actionDefinitions.forEach(function(action){
logging.verbose("Action", action);
if (action.advanced && !settings.displayAdvancedSettings){
logging.verbose("Hiding advanced action");
@ -59,16 +127,23 @@
const icon = document.createElement("span");
icon.className = "icon";
icon.style.maskImage = "url(" + action.icon + ")";
function setIcon(url){
icon.style.maskImage = "url(" + url + ")";
}
setIcon(action.icon);
actionButton.appendChild(icon);
actionButton.appendChild(
document.createTextNode(
extension.getTranslation("browserAction_" + action.label) || action.label
)
);
actionButton.addEventListener("click", action.action);
const textNode = document.createTextNode("");
function setLabel(label){
textNode.nodeValue = extension.getTranslation("browserAction_" + label) || label;
}
setLabel(action.label);
actionButton.appendChild(textNode);
actionButton.addEventListener("click", function(){
action.action.call(this, {setIcon, setLabel});
});
actions.appendChild(actionButton);
});
@ -80,13 +155,17 @@
search.addEventListener("keypress", function(event){
if ([10, 13].indexOf(event.keyCode) !== -1){
window.open(browser.extension.getURL(
browser.tabs.create({url: extension.getURL(
"options/options.html" +
"?search=" +
encodeURIComponent(this.value)
));
)});
window.close();
}
});
});
window.addEventListener("load", async function(){
extension.displayVersion("version", 250);
});
}());

View File

@ -1,3 +1,8 @@
files:
- source: /_locales/en/*.json
translation: /_locales/%two_letters_code%/%original_file_name%
languages_mapping:
two_letters_code:
zh-CN: zh_CN
pt-BR: pt_BR
zh-TW: zh_TW

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="svg2" inkscape:version="0.92.2 2405546, 2018-03-11" sodipodi:docname="browserAction-whitelisted.svg" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="96px" height="96px"
viewBox="0 0 96 96" enable-background="new 0 0 96 96" xml:space="preserve">
<sodipodi:namedview id="namedview9" inkscape:pageshadow="2" inkscape:window-width="1600" inkscape:window-height="841" inkscape:current-layer="svg2" inkscape:window-x="0" inkscape:window-y="0" inkscape:pageopacity="0" gridtolerance="10" inkscape:cx="-19.539638" objecttolerance="10" inkscape:zoom="3.4766083" borderopacity="1" showgrid="false" bordercolor="#666666" guidetolerance="10" pagecolor="#ffffff" inkscape:cy="53.605992" inkscape:window-maximized="1">
</sodipodi:namedview>
<path id="rect3826" fill="#F5F5F5" d="M23.808,2h48.385C84.236,2,94,11.764,94,23.808v48.385C94,84.236,84.236,94,72.191,94H23.808
C11.764,94,2,84.236,2,72.191V23.808C2,11.764,11.764,2,23.808,2z"/>
<path id="path4138" inkscape:connector-curvature="0" fill="#5C5C5C" d="M30.141,82.826c0.456,0.027,1.107-0.164,1.411-0.412
c0.139-0.113,0.567-0.551,0.953-0.971c1.881-2.055,3.544-2.898,4.942-2.512c1.059,0.295,2.344,2.311,3.471,5.438
c0.671,1.862,1.018,2.272,2.078,2.461c0.646,0.106,1.577-0.211,1.949-0.677c0.786-0.982,0.744-1.581-0.297-4.195
c-1.14-2.859-2.118-4.486-3.483-5.796c-0.557-0.533-0.688-0.608-1.792-1.093c-1.115-0.48-1.25-0.521-2.083-0.574
c-1.22-0.079-1.971,0.035-3.196,0.482c-1.626,0.603-3.177,1.717-4.734,3.402c-0.836,0.906-1.096,1.307-1.206,1.854
C27.903,81.493,28.871,82.75,30.141,82.826z M22.995,76.758c0.63-0.013,2.712-0.607,4.185-1.197c2.96-1.186,5.259-2.843,6.942-5.006
c1.732-2.223,2.766-5.514,2.534-8.063c-0.14-1.537-1.171-2.426-2.56-2.204c-1.155,0.185-1.846,1.142-1.794,2.487
c0.05,1.305-0.112,2.123-0.675,3.406c-0.385,0.877-0.617,1.291-0.996,1.769c-0.619,0.78-1.767,1.784-2.752,2.403
c-0.96,0.604-3.115,1.506-4.52,1.896c-1.711,0.474-2.105,0.747-2.419,1.679C20.476,75.309,21.548,76.785,22.995,76.758
L22.995,76.758z M51.635,88.271c0.777,0.125,1.611-0.181,2.063-0.742c0.357-0.449,0.572-1.219,0.482-1.725
c-0.047-0.264-0.535-1.229-1.246-2.457C47.646,74.152,43.52,64.589,41.913,57.8c-0.611-2.579-0.907-5.196-0.801-7.098
c0.148-2.679,0.969-4.377,2.944-6.095c1.762-1.532,3.848-1.911,5.826-1.057c1.743,0.751,3.076,2.407,3.571,4.432
c0.115,0.471,0.252,1.868,0.331,3.375c0.401,7.607,1.776,12.148,5.877,19.398c1.379,2.438,4.983,8.372,5.26,8.658
c0.401,0.418,1.349,0.727,1.919,0.621c1.196-0.217,2.012-1.457,1.729-2.645c-0.047-0.197-0.654-1.31-1.354-2.465
c-4.361-7.22-5.924-10.104-7.027-13.035c-1.252-3.308-1.752-5.979-2.022-10.822c-0.16-2.871-0.322-3.906-0.828-5.317
c-1.099-3.067-3.728-5.678-6.591-6.551c-2.245-0.684-4.219-0.622-6.348,0.198c-2.368,0.913-4.308,2.545-5.829,4.908
c-0.639,0.992-1.221,2.44-1.507,3.751c-0.764,3.5-0.163,8.708,1.692,14.667c1.689,5.424,4.678,12.258,8.348,19.088
c1.315,2.444,2.89,5.198,3.224,5.629C50.621,87.842,51.201,88.205,51.635,88.271L51.635,88.271z M16.767,68.199
c1.446,0.063,3.005-0.068,4.184-0.352c3.642-0.882,7.026-3.611,9.745-7.875c1.634-2.563,2.318-4.521,3.509-10.057
c1.172-5.442,2.109-7.967,3.715-10.011c1.779-2.264,4.521-3.784,7.851-4.353c2.52-0.429,4.891-0.146,7.23,0.864
c2.353,1.015,4.129,2.524,5.588,4.745c1.854,2.821,2.699,5.881,2.933,10.604c0.065,1.353,0.201,2.918,0.307,3.479
c0.688,3.884,2.863,8.895,5.92,13.621c0.916,1.419,1.207,1.744,1.771,1.988c1.646,0.711,3.463-0.881,2.918-2.563
c-0.076-0.231-0.453-0.908-0.842-1.498c-2.794-4.276-4.837-8.867-5.479-12.313c-0.08-0.438-0.163-1.318-0.185-1.963
c-0.133-4.199-0.59-6.895-1.646-9.699c-1.692-4.485-4.479-7.75-8.464-9.903c-3.773-2.044-8.651-2.458-13.146-1.115
c-5.404,1.616-9.096,5.196-11.024,10.692c-0.607,1.731-1.005,3.23-1.692,6.383c-0.791,3.628-1.068,4.646-1.708,6.272
c-0.496,1.265-0.673,1.619-1.226,2.455c-1.98,2.989-3.854,4.75-5.994,5.623c-1.19,0.48-2.282,0.647-4.036,0.611
c-1.452-0.027-1.799,0.037-2.299,0.449c-0.739,0.607-1,1.592-0.647,2.441C14.468,67.754,15.168,68.129,16.767,68.199z M59.887,85.92
c0.512-0.016,0.977-0.203,1.449-0.588c0.332-0.27,0.672-1.158,0.635-1.663c-0.039-0.546-0.158-0.802-1.128-2.423
c-4.798-8.023-8.554-16.719-10.219-23.664c-0.656-2.736-0.978-4.822-1.11-7.225c-0.078-1.395-0.127-1.67-0.354-2.042
c-0.219-0.346-0.375-0.48-0.848-0.716c-0.381-0.191-0.708-0.283-0.942-0.294c-1.189-0.013-2.147,0.904-2.231,2.132
c-0.043,0.636,0.108,2.902,0.277,4.158c1.131,8.401,5.262,19.021,11.536,29.646c0.567,0.964,1.172,1.891,1.34,2.059
C58.714,85.734,59.246,85.938,59.887,85.92L59.887,85.92z M14.583,61.125c0.586-0.031,2.742-0.874,4.285-1.674
c1.912-0.99,3.742-2.354,4.875-3.629c0.981-1.105,1.427-1.824,2.097-3.387c0.732-1.707,0.892-2.229,2.144-7.027
c1.272-4.877,1.599-5.944,2.381-7.763c0.754-1.753,1.157-2.384,2.252-3.528c0.693-0.725,2.023-1.881,2.895-2.519
c2.495-1.823,5.927-3.274,8.839-3.737c6.736-1.071,14.553,1.754,18.793,6.792c1.271,1.517,2.273,3.206,3.144,5.3
c1,2.419,1.549,4.663,2.187,8.936c0.336,2.241,0.695,3.818,1.256,5.479c0.899,2.672,2.705,5.885,3.646,6.496
c0.739,0.479,1.938,0.368,2.604-0.236c0.18-0.161,0.406-0.493,0.521-0.754c0.354-0.813,0.248-1.536-0.35-2.337
c-0.592-0.796-1.432-2.38-1.93-3.637c-0.8-2.012-1.113-3.368-1.652-7.07c-0.938-6.443-2.918-11.259-6.196-15.068
c-2.198-2.553-4.604-4.357-7.858-5.901c-5.721-2.709-11.805-3.296-17.592-1.696c-4.545,1.257-9.443,4.404-12.359,7.941
c-0.997,1.21-1.276,1.7-2.223,3.907c-1.008,2.352-1.2,2.962-2.501,7.973c-1.507,5.809-2,7.213-2.963,8.454
c-1.16,1.496-3.207,2.865-6.102,4.084c-1.705,0.722-2.043,0.949-2.319,1.588C11.812,59.604,12.948,61.215,14.583,61.125
L14.583,61.125z M16.24,52.795c0.483,0.055,1.019-0.072,1.441-0.348c0.606-0.393,0.871-0.975,1.224-2.689
c1.364-6.627,3.764-12.456,6.843-16.617c0.599-0.81,0.96-1.228,1.792-2.076c1.003-1.021,1.213-1.806,0.752-2.811
c-0.614-1.339-2.258-1.645-3.459-0.643c-0.925,0.771-2.451,2.626-3.626,4.407c-2.578,3.906-4.743,9.102-6.082,14.591
c-0.455,1.863-0.815,3.732-0.801,4.146C14.359,51.752,15.23,52.678,16.24,52.795L16.24,52.795z M77.986,50.193
c0.961,0.14,1.797-0.314,2.26-1.229c0.326-0.641,0.309-1-0.189-3.746c-0.914-5.066-2.465-10.016-4.086-13.047
c-2.645-4.948-6.426-8.803-11.617-11.844c-1.438-0.847-4.939-2.44-6.442-2.938c-6.185-2.042-12.656-2.134-19.49-0.278
c-2.937,0.798-7.896,2.919-9.62,4.115c-0.965,0.67-1.278,1.718-0.809,2.71c0.53,1.121,1.613,1.56,2.716,1.102
c0.315-0.131,1.1-0.529,1.743-0.884c1.418-0.784,5.004-2.234,6.736-2.724c7.333-2.072,14.103-1.64,20.314,1.298
c5.229,2.475,8.858,5.515,11.537,9.662c2.168,3.365,3.647,7.662,4.71,13.635c0.521,2.965,0.521,2.974,0.88,3.377
C77.049,49.893,77.426,50.111,77.986,50.193L77.986,50.193z M81.521,35.5c1.049-0.005,1.99-0.758,2.176-1.744
c0.117-0.623-0.105-1.528-0.82-3.338c-2.076-5.25-5.73-10.019-10.551-13.767c-4.316-3.356-9.973-5.997-15.771-7.365
C52.813,8.404,48.351,8.09,44.511,8.44c-1.835,0.167-4.559,0.642-6.361,1.109c-1.521,0.395-2.014,0.709-2.351,1.499
c-0.576,1.351,0.384,2.922,1.839,3.013c0.196,0.012,1.036-0.144,1.867-0.347c3.635-0.888,6.941-1.216,10.265-1.017
c7.313,0.437,15.016,3.396,20.502,7.883c4.207,3.437,7.521,8.089,8.979,12.609c0.271,0.842,0.504,1.368,0.694,1.58
C80.284,35.141,81.063,35.502,81.521,35.5L81.521,35.5z"/>
<linearGradient id="rect3826-9_1_" gradientUnits="userSpaceOnUse" x1="-2884.5107" y1="2237.3203" x2="-2884.0027" y2="2328.032" gradientTransform="matrix(-1.0612 0 0 1 -3035.2104 -2234.4375)">
<stop offset="0" style="stop-color:#808080;stop-opacity:0"/>
<stop offset="0.6455" style="stop-color:#808080;stop-opacity:0.498"/>
<stop offset="0.8787" style="stop-color:#808080"/>
<stop offset="1" style="stop-color:#808080"/>
</linearGradient>
<path id="rect3826-9" inkscape:connector-curvature="0" opacity="0.6" fill="url(#rect3826-9_1_)" enable-background="new " d="
M48,3v90H26.146C13.326,93,3,83.27,3,71.188V24.813C3,12.731,13.326,3,26.146,3H48z"/>
<path id="rect3826-4" inkscape:connector-curvature="0" opacity="0.6" fill="#808080" enable-background="new " d="M71.188,3
C83.27,3,93,12.731,93,24.813v46.375C93,83.27,83.27,93,71.188,93H48V3H71.188z"/>
<path id="rect3826-0" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M23.808,2
h48.385C84.236,2,94,11.764,94,23.808v48.385C94,84.236,84.236,94,72.191,94H23.808C11.764,94,2,84.236,2,72.191V23.808
C2,11.764,11.764,2,23.808,2z"/>
<g id="Loeschen">
<g id="XMLID_1_">
<g>
<path fill="#FFFFFF" d="M82.62,69.56c0,4.221-1.64,8.19-4.63,11.181c-2.98,2.979-6.95,4.63-11.181,4.63
c-4.22,0-8.189-1.65-11.18-4.63C52.64,77.75,51,73.78,51,69.56c0-4.229,1.64-8.199,4.63-11.18c2.98-2.99,6.96-4.64,11.18-4.64
c4.23,0,8.19,1.649,11.181,4.64c1.49,1.49,2.649,3.23,3.439,5.12C82.21,65.4,82.62,67.44,82.62,69.56z M76,64.61l-4.24-4.25
l-4.95,4.949L61.86,60.37l-4.24,4.24l4.95,4.949l-4.95,4.95l4.24,4.24l4.949-4.95l4.95,4.95L76,74.51l-4.95-4.95L76,64.61z"/>
<polygon fill="#FF0000" points="71.76,60.36 76,64.61 71.05,69.56 76,74.51 71.76,78.75 66.81,73.8 61.86,78.75 57.62,74.51
62.57,69.56 57.62,64.61 61.86,60.37 66.81,65.31 "/>
<path fill="#FF0000" d="M82.62,69.56c0-2.119-0.41-4.159-1.19-6.06c-0.79-1.89-1.949-3.63-3.439-5.12
c-2.99-2.99-6.95-4.64-11.181-4.64c-4.22,0-8.199,1.649-11.18,4.64C52.64,61.36,51,65.33,51,69.56c0,4.221,1.64,8.19,4.63,11.181
c2.99,2.979,6.96,4.63,11.18,4.63c4.23,0,8.2-1.65,11.181-4.63C80.98,77.75,82.62,73.78,82.62,69.56z M80.06,56.31
c7.32,7.311,7.32,19.181,0,26.5C76.4,86.47,71.61,88.3,66.81,88.3c-4.79,0-9.59-1.83-13.25-5.49
c-7.319-7.319-7.319-19.189,0-26.5c3.66-3.659,8.46-5.489,13.25-5.489C71.61,50.82,76.4,52.65,80.06,56.31z"/>
</g>
<g>
<polygon fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" points="71.76,60.36
66.81,65.31 61.86,60.37 57.62,64.61 62.57,69.56 57.62,74.51 61.86,78.75 66.81,73.8 71.76,78.75 76,74.51 71.05,69.56
76,64.61 "/>
<path fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" d="M80.06,56.31
C76.4,52.65,71.61,50.82,66.81,50.82c-4.79,0-9.59,1.83-13.25,5.489c-7.319,7.311-7.319,19.181,0,26.5
c3.66,3.66,8.46,5.49,13.25,5.49c4.801,0,9.591-1.83,13.25-5.49C87.38,75.49,87.38,63.62,80.06,56.31z"/>
<path fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" d="M77.99,80.74
c-2.98,2.979-6.95,4.63-11.181,4.63c-4.22,0-8.189-1.65-11.18-4.63C52.64,77.75,51,73.78,51,69.56c0-4.229,1.64-8.199,4.63-11.18
c2.98-2.99,6.96-4.64,11.18-4.64c4.23,0,8.19,1.649,11.181,4.64c1.49,1.49,2.649,3.23,3.439,5.12c0.78,1.9,1.19,3.94,1.19,6.06
C82.62,73.78,80.98,77.75,77.99,80.74z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="svg2" inkscape:version="0.92.2 2405546, 2018-03-11" sodipodi:docname="browserAction-notPrinted.svg" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="96px" height="96px"
viewBox="0 0 96 96" enable-background="new 0 0 96 96" xml:space="preserve">
<sodipodi:namedview id="namedview9" inkscape:pageshadow="2" inkscape:window-width="1600" inkscape:window-height="841" inkscape:current-layer="svg2" inkscape:window-x="0" inkscape:window-y="0" inkscape:pageopacity="0" gridtolerance="10" inkscape:cx="-39.24275" objecttolerance="10" inkscape:zoom="3.4766083" borderopacity="1" showgrid="false" bordercolor="#666666" guidetolerance="10" pagecolor="#ffffff" inkscape:cy="53.605992" inkscape:window-maximized="1">
</sodipodi:namedview>
<path id="rect3826" fill="#F5F5F5" d="M23.808,2h48.385C84.236,2,94,11.764,94,23.808v48.385C94,84.236,84.236,94,72.191,94H23.808
C11.764,94,2,84.236,2,72.191V23.808C2,11.764,11.764,2,23.808,2z"/>
<path id="path4138" inkscape:connector-curvature="0" fill="#5C5C5C" d="M30.141,82.826c0.456,0.027,1.107-0.164,1.411-0.412
c0.139-0.113,0.567-0.551,0.953-0.971c1.881-2.055,3.544-2.898,4.942-2.512c1.059,0.295,2.344,2.311,3.471,5.439
c0.671,1.863,1.018,2.273,2.078,2.461c0.646,0.107,1.577-0.211,1.949-0.676c0.786-0.983,0.744-1.582-0.297-4.196
c-1.14-2.86-2.118-4.487-3.483-5.796c-0.557-0.533-0.688-0.609-1.792-1.092c-1.115-0.481-1.25-0.521-2.083-0.575
c-1.22-0.079-1.971,0.035-3.196,0.483c-1.626,0.602-3.177,1.717-4.734,3.402c-0.836,0.906-1.096,1.307-1.206,1.854
C27.903,81.493,28.871,82.75,30.141,82.826z M22.995,76.758c0.63-0.013,2.712-0.607,4.185-1.197c2.96-1.186,5.259-2.843,6.942-5.006
c1.732-2.223,2.766-5.514,2.534-8.063c-0.14-1.537-1.171-2.426-2.56-2.204c-1.155,0.185-1.846,1.142-1.794,2.487
c0.05,1.305-0.112,2.123-0.675,3.406c-0.385,0.877-0.617,1.291-0.996,1.769c-0.619,0.78-1.767,1.784-2.752,2.403
c-0.96,0.604-3.115,1.506-4.52,1.896c-1.711,0.474-2.105,0.747-2.419,1.679C20.476,75.309,21.548,76.785,22.995,76.758
L22.995,76.758z M51.635,88.271c0.777,0.125,1.611-0.18,2.063-0.742c0.357-0.449,0.572-1.219,0.482-1.725
c-0.047-0.263-0.535-1.228-1.246-2.457C47.646,74.152,43.52,64.589,41.913,57.8c-0.611-2.579-0.907-5.196-0.801-7.098
c0.148-2.679,0.969-4.377,2.944-6.095c1.762-1.532,3.848-1.911,5.826-1.057c1.743,0.751,3.076,2.407,3.571,4.432
c0.115,0.471,0.252,1.868,0.331,3.375c0.401,7.608,1.776,12.149,5.877,19.399c1.379,2.438,4.983,8.372,5.26,8.658
c0.401,0.418,1.349,0.726,1.919,0.621c1.196-0.216,2.012-1.457,1.729-2.644c-0.047-0.197-0.655-1.31-1.354-2.465
c-4.362-7.22-5.924-10.104-7.028-13.035c-1.252-3.308-1.752-5.979-2.022-10.822c-0.16-2.872-0.322-3.907-0.828-5.318
c-1.099-3.067-3.728-5.678-6.591-6.551c-2.245-0.684-4.219-0.622-6.348,0.198c-2.368,0.913-4.308,2.545-5.829,4.908
c-0.639,0.992-1.221,2.44-1.507,3.751c-0.764,3.5-0.163,8.708,1.692,14.667c1.689,5.424,4.678,12.258,8.348,19.088
c1.315,2.445,2.89,5.199,3.224,5.629C50.621,87.842,51.201,88.205,51.635,88.271L51.635,88.271z M16.767,68.199
c1.446,0.063,3.005-0.068,4.184-0.352c3.642-0.881,7.026-3.611,9.745-7.875c1.634-2.563,2.318-4.521,3.509-10.056
c1.172-5.442,2.109-7.967,3.715-10.011c1.779-2.264,4.521-3.784,7.851-4.352c2.52-0.429,4.891-0.146,7.23,0.864
c2.353,1.015,4.129,2.524,5.588,4.745c1.854,2.821,2.699,5.881,2.933,10.603c0.065,1.353,0.201,2.918,0.306,3.479
c0.688,3.884,2.864,8.895,5.92,13.621c0.916,1.419,1.207,1.744,1.771,1.988c1.646,0.711,3.463-0.881,2.918-2.563
c-0.076-0.231-0.453-0.908-0.842-1.498c-2.793-4.276-4.836-8.867-5.479-12.313c-0.08-0.438-0.163-1.319-0.184-1.963
c-0.133-4.199-0.59-6.895-1.646-9.699c-1.692-4.485-4.479-7.75-8.463-9.903c-3.774-2.044-8.652-2.458-13.146-1.115
c-5.404,1.616-9.096,5.196-11.024,10.692c-0.607,1.731-1.005,3.23-1.692,6.383c-0.791,3.628-1.068,4.646-1.708,6.272
c-0.496,1.265-0.673,1.619-1.226,2.455c-1.98,2.99-3.854,4.75-5.994,5.623c-1.19,0.481-2.282,0.648-4.036,0.612
c-1.452-0.028-1.799,0.037-2.299,0.449c-0.739,0.608-1,1.592-0.647,2.442C14.468,67.754,15.168,68.129,16.767,68.199z M59.887,85.92
c0.512-0.016,0.977-0.203,1.449-0.588c0.332-0.27,0.672-1.158,0.635-1.663c-0.039-0.546-0.158-0.802-1.128-2.423
c-4.798-8.023-8.554-16.719-10.219-23.664c-0.656-2.736-0.978-4.822-1.11-7.225c-0.078-1.394-0.127-1.67-0.354-2.042
c-0.219-0.346-0.375-0.48-0.848-0.716c-0.381-0.191-0.708-0.283-0.942-0.294c-1.189-0.013-2.147,0.904-2.231,2.133
c-0.043,0.635,0.108,2.902,0.277,4.158c1.131,8.401,5.262,19.02,11.536,29.646c0.567,0.964,1.172,1.891,1.34,2.059
C58.714,85.734,59.246,85.938,59.887,85.92L59.887,85.92z M14.583,61.125c0.586-0.031,2.742-0.874,4.285-1.674
c1.912-0.99,3.742-2.354,4.875-3.629c0.981-1.105,1.427-1.824,2.097-3.387c0.732-1.707,0.892-2.229,2.144-7.027
c1.272-4.877,1.599-5.944,2.381-7.763c0.754-1.753,1.157-2.384,2.252-3.528c0.693-0.725,2.023-1.881,2.895-2.519
c2.495-1.823,5.927-3.274,8.839-3.737c6.736-1.071,14.553,1.754,18.793,6.792c1.272,1.517,2.274,3.206,3.144,5.3
c1,2.419,1.549,4.663,2.187,8.936c0.336,2.241,0.695,3.818,1.256,5.479c0.899,2.672,2.705,5.885,3.646,6.496
c0.739,0.479,1.938,0.368,2.604-0.236c0.179-0.161,0.406-0.493,0.521-0.754c0.354-0.813,0.248-1.536-0.35-2.337
c-0.592-0.796-1.432-2.38-1.93-3.637c-0.799-2.012-1.113-3.368-1.652-7.07c-0.938-6.443-2.918-11.259-6.196-15.068
c-2.198-2.553-4.604-4.357-7.858-5.901c-5.721-2.709-11.805-3.296-17.592-1.696c-4.545,1.257-9.443,4.404-12.359,7.941
c-0.997,1.21-1.276,1.7-2.223,3.907c-1.008,2.352-1.2,2.962-2.501,7.973c-1.507,5.809-2,7.213-2.963,8.454
c-1.16,1.496-3.207,2.865-6.102,4.084c-1.705,0.721-2.043,0.949-2.319,1.588C11.812,59.604,12.948,61.215,14.583,61.125
L14.583,61.125z M16.24,52.795c0.483,0.055,1.019-0.072,1.441-0.348c0.606-0.393,0.871-0.975,1.224-2.689
c1.364-6.627,3.764-12.456,6.843-16.617c0.599-0.81,0.96-1.228,1.792-2.076c1.003-1.021,1.213-1.806,0.752-2.811
c-0.614-1.339-2.258-1.645-3.459-0.643c-0.925,0.771-2.451,2.626-3.626,4.407c-2.578,3.906-4.743,9.102-6.082,14.591
c-0.455,1.863-0.815,3.732-0.801,4.146C14.359,51.752,15.23,52.678,16.24,52.795L16.24,52.795z M77.986,50.193
c0.961,0.14,1.797-0.314,2.26-1.229c0.326-0.641,0.309-1-0.189-3.746c-0.914-5.066-2.465-10.016-4.086-13.047
c-2.645-4.948-6.426-8.803-11.617-11.844c-1.439-0.847-4.94-2.44-6.443-2.938c-6.184-2.042-12.656-2.134-19.49-0.278
c-2.937,0.798-7.896,2.919-9.62,4.115c-0.965,0.67-1.278,1.718-0.809,2.71c0.53,1.121,1.613,1.56,2.716,1.102
c0.315-0.131,1.1-0.529,1.743-0.884c1.418-0.784,5.004-2.234,6.736-2.724c7.333-2.072,14.103-1.64,20.314,1.298
c5.23,2.475,8.859,5.515,11.537,9.662c2.168,3.365,3.648,7.662,4.71,13.635c0.521,2.965,0.522,2.974,0.88,3.377
C77.049,49.893,77.426,50.111,77.986,50.193L77.986,50.193z M81.521,35.5c1.049-0.005,1.99-0.758,2.176-1.744
c0.117-0.623-0.105-1.528-0.82-3.338c-2.076-5.25-5.73-10.019-10.551-13.767c-4.316-3.356-9.973-5.997-15.771-7.365
C52.813,8.404,48.351,8.09,44.511,8.44c-1.835,0.167-4.559,0.642-6.361,1.109c-1.521,0.395-2.014,0.709-2.351,1.499
c-0.576,1.351,0.384,2.922,1.839,3.013c0.196,0.012,1.036-0.144,1.867-0.347c3.635-0.888,6.941-1.216,10.265-1.017
c7.313,0.437,15.015,3.396,20.502,7.883c4.207,3.437,7.521,8.089,8.979,12.609c0.271,0.842,0.504,1.368,0.694,1.58
C80.284,35.141,81.063,35.502,81.521,35.5L81.521,35.5z"/>
<linearGradient id="rect3826-9_1_" gradientUnits="userSpaceOnUse" x1="-2392.2759" y1="-1420.481" x2="-2391.7678" y2="-1511.1927" gradientTransform="matrix(-1.0612 0 0 -1 -2512.8511 -1417.5977)">
<stop offset="0" style="stop-color:#0050BF;stop-opacity:0"/>
<stop offset="0.6455" style="stop-color:#0050BF;stop-opacity:0.498"/>
<stop offset="0.8787" style="stop-color:#0050BF"/>
<stop offset="1" style="stop-color:#0050BF"/>
</linearGradient>
<path id="rect3826-9" inkscape:connector-curvature="0" opacity="0.5" fill="url(#rect3826-9_1_)" enable-background="new " d="
M48,3v90H26.146C13.326,93,3,83.27,3,71.188V24.813C3,12.731,13.326,3,26.146,3H48z"/>
<path id="rect3826-4" inkscape:connector-curvature="0" opacity="0.5" fill="#004FBD" enable-background="new " d="M71.188,3
C83.27,3,93,12.731,93,24.813v46.375C93,83.27,83.27,93,71.188,93H48V3H71.188z"/>
<path id="rect3826-0" fill="none" stroke="#000000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" d="M23.808,2
h48.385C84.236,2,94,11.764,94,23.808v48.385C94,84.236,84.236,94,72.191,94H23.808C11.764,94,2,84.236,2,72.191V23.808
C2,11.764,11.764,2,23.808,2z"/>
<g id="Haekchen">
<g id="XMLID_1_">
<g>
<path fill="#FFFFFF" d="M78.01,58.39c6.16,6.17,6.16,16.19,0,22.36c-2.99,2.98-6.96,4.62-11.18,4.62s-8.19-1.64-11.17-4.62
c-6.16-6.17-6.16-16.19,0-22.36c2.979-2.979,6.95-4.62,11.17-4.62S75.02,55.41,78.01,58.39z M77.78,65l-3.11-3.16l-10.4,8.63
l-3.859-4.2l-4.271,4.28l8.04,8.04L77.78,65z"/>
<polygon fill="#58E617" points="74.67,61.84 77.78,65 64.18,78.59 56.14,70.55 60.41,66.27 64.27,70.47 "/>
<path fill="#58E617" d="M78.01,80.75c6.16-6.17,6.16-16.19,0-22.36c-2.99-2.979-6.96-4.62-11.18-4.62s-8.19,1.641-11.17,4.62
c-6.16,6.17-6.16,16.19,0,22.36c2.979,2.98,6.95,4.62,11.17,4.62S75.02,83.73,78.01,80.75z M80.08,56.33
c7.31,7.31,7.31,19.17,0,26.479c-3.66,3.66-8.46,5.49-13.25,5.49s-9.58-1.83-13.24-5.49c-7.32-7.31-7.32-19.17,0-26.479
c3.66-3.66,8.45-5.49,13.24-5.49S76.42,52.67,80.08,56.33z"/>
</g>
<g>
<path fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" d="M80.08,56.33
c-3.66-3.66-8.46-5.49-13.25-5.49s-9.58,1.83-13.24,5.49c-7.32,7.31-7.32,19.17,0,26.479c3.66,3.66,8.45,5.49,13.24,5.49
s9.59-1.83,13.25-5.49C87.39,75.5,87.39,63.64,80.08,56.33z"/>
<path fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" d="M78.01,80.75
c-2.99,2.98-6.96,4.62-11.18,4.62s-8.19-1.64-11.17-4.62c-6.16-6.17-6.16-16.19,0-22.36c2.979-2.979,6.95-4.62,11.17-4.62
s8.189,1.641,11.18,4.62C84.17,64.56,84.17,74.58,78.01,80.75z"/>
<polygon fill="none" stroke="#000000" stroke-width="0.5" stroke-linejoin="round" stroke-miterlimit="10" points="64.27,70.47
60.41,66.27 56.14,70.55 64.18,78.59 77.78,65 74.67,61.84 "/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

100
icons/browserAction-faq.svg Normal file
View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
width="38"
height="38"
viewBox="0 0 38 38"
sodipodi:docname="browserAction-faq.svg"
inkscape:export-filename="Fingerprint.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="841"
id="namedview4"
showgrid="false"
inkscape:zoom="8.8685035"
inkscape:cx="-5.5444943"
inkscape:cy="22.071382"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
showguides="true">
<inkscape:grid
type="xygrid"
id="grid3725" />
</sodipodi:namedview>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#919191;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 19,0 C 8.5272756,0 0,8.5272748 0,19 0,29.472725 8.5272756,38 19,38 29.472724,38 38,29.472725 38,19 38,8.5272748 29.472724,0 19,0 Z m 0,3.5 c 8.581184,0 15.5,6.918815 15.5,15.5 0,8.581185 -6.918816,15.5 -15.5,15.5 C 10.418816,34.5 3.5,27.581185 3.5,19 3.5,10.418815 10.418816,3.5 19,3.5 Z"
id="path819"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#bbbbbb;fill-opacity:1;stroke:none"
x="10.982422"
y="33.580078"
id="text823"><tspan
sodipodi:role="line"
id="tspan821"
x="10.982422"
y="68.970703"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:AkrutiMal2;-inkscape-font-specification:AkrutiMal2" /></text>
<circle
style="opacity:1;fill:#919191;fill-opacity:1;stroke:#bbbbbb;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path831"
cx="19"
cy="27.772472"
r="3.9999993" />
<path
style="fill:none;stroke:#919191;stroke-width:6.30000019;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 12.290687,12.178281 c 0,0 2.914851,-4.0593089 6.314481,-4.0593088 3.382758,0 5.57748,1.9006158 5.750689,4.2848258 0.142504,1.961563 -3.177558,2.475312 -4.172068,4.172069 -0.770156,1.313982 -1.240343,2.139595 -1.240344,4.397584 l -1e-6,1.691379"
id="path817"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csaasc" />
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
id="svg2"
version="1.1"
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
width="38"
height="38"
viewBox="0 0 38 38"
sodipodi:docname="browserAction-reload.svg"
inkscape:export-filename="Fingerprint.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="841"
id="namedview4"
showgrid="false"
inkscape:zoom="8.8685035"
inkscape:cx="0.62017228"
inkscape:cy="22.044305"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
showguides="true"
inkscape:pagecheckerboard="0">
<inkscape:grid
type="xygrid"
id="grid3725" />
</sodipodi:namedview>
<path
id="path819"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#919191;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.5;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 27.558376,2.036681 C 18.208263,-2.6806621 6.7540244,1.0915089 2.036681,10.441624 c -4.7173433,9.350114 -0.9451714,20.804352 8.404943,25.521695 9.350113,4.717343 20.804352,0.945172 25.521695,-8.404943 1.490789,-2.95485 2.131192,-6.119738 2.017806,-9.215679 l -3.48287,0.09573 c 0.09126,2.528509 -0.436066,5.11796 -1.659758,7.543405 -3.865316,7.661336 -13.158996,10.72198 -20.82033,6.856664 C 4.3568317,28.973181 1.2961865,19.679502 5.1615029,12.018167 9.0268193,4.3568308 18.320499,1.2961869 25.981833,5.1615029 27.491656,5.9232425 28.81983,6.8983886 29.954505,8.027729 L 32.30738,5.4367801 C 30.943863,4.0966388 29.353902,2.942564 27.558376,2.036681 Z" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#bbbbbb;fill-opacity:1;stroke:none"
x="10.982422"
y="33.580078"
id="text823"><tspan
sodipodi:role="line"
id="tspan821"
x="10.982422"
y="68.970703"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:AkrutiMal2;-inkscape-font-specification:AkrutiMal2" /></text>
<g
id="g180"
transform="matrix(-0.67598944,-0.06825165,0.06825165,-0.67598944,43.19324,21.507957)"
style="stroke-width:1.47183">
<rect
style="fill:#919191;fill-opacity:1;stroke:#919191;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect829"
width="5.999999"
height="16.195862"
x="15.780028"
y="-28.064632"
transform="rotate(82.446816)" />
<rect
style="fill:#919191;fill-opacity:1;stroke:#919191;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect829-3"
width="5.999999"
height="16.195862"
x="-18.228109"
y="-31.699099"
transform="rotate(173.76303)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@ -67,26 +67,5 @@
d="m 14.012442,1035.5221 c -2.335232,-2.4003 -6.181514,-2.4678 -8.563982,-0.1499 -2.382415,2.3178 -2.409607,6.1539 -0.07438,8.5542 2.083652,2.1417 5.370014,2.4455 7.746402,0.8391 l 6.980535,7.1749 1.507034,-1.4662 -6.980536,-7.1749 c 1.672964,-2.3332 1.468573,-5.6355 -0.615078,-7.7772 z m -1.048412,1.02 c 1.790326,1.8402 1.762992,4.7471 -0.04629,6.5074 -1.809231,1.7602 -4.704915,1.6971 -6.495242,-0.1431 -1.790325,-1.8402 -1.763281,-4.7256 0.04595,-6.4858 1.809283,-1.7603 4.705256,-1.7186 6.495583,0.1215 z"
id="path2985"
inkscape:connector-curvature="0" />
<rect
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect3955-51"
width="10"
height="2"
x="-24.180271"
y="1033.5027" />
<rect
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect3955-4-7"
width="10"
height="2"
x="-24.180271"
y="1030.5026" />
<rect
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect3955-5-1"
width="10"
height="2"
x="-24.180271"
y="1027.5026" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -52,18 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-size:144px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="-4.8717484"
y="1008.9256"
id="text3755"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3757"
x="-4.8717484"
y="1008.9256"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">www.</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.1668789,1040.8717 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.3550471,-9.0615 7.0710681,-13.3846"

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -52,18 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-size:144px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="-4.8717484"
y="1008.9256"
id="text3755"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3757"
x="-4.8717484"
y="1008.9256"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">www.</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.1668789,1040.8717 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.3550471,-9.0615 7.0710681,-13.3846"

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -52,17 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
x="-4.8717484"
y="1008.9256"
id="text3755"><tspan
sodipodi:role="line"
id="tspan3757"
x="-4.8717484"
y="1008.9256"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:1.25;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman';text-align:start;text-anchor:start">www.</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.1668789,1040.8717 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.3550471,-9.0615 7.0710681,-13.3846"

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -52,17 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
x="-4.8717484"
y="1008.9256"
id="text3755"><tspan
sodipodi:role="line"
id="tspan3757"
x="-4.8717484"
y="1008.9256"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:1.25;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman';text-align:start;text-anchor:start">www.</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.1668789,1040.8717 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.3550471,-9.0615 7.0710681,-13.3846"

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -52,18 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-size:144px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="4.5984316"
y="1006.9256"
id="text3755"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3757"
x="4.5984316"
y="1006.9256"
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;text-anchor:start;font-family:Times New Roman;-inkscape-font-specification:Times New Roman">https:</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.167,1040.8719 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.355047,-9.0615 7.071068,-13.3846"

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -52,17 +52,6 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1033.3622)">
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
x="4.5984316"
y="1006.9256"
id="text3755"><tspan
sodipodi:role="line"
id="tspan3757"
x="4.5984316"
y="1006.9256"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:1.25;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman';text-align:start;text-anchor:start">https:</tspan></text>
<path
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.167,1040.8719 c 2.65165,3.1567 3.661803,3.788 4.293148,8.5863 0.883884,-3.7881 2.355047,-9.0615 7.071068,-13.3846"

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -88,7 +88,8 @@
audio: _("askForAudioPermission"),
history: _("askForHistoryPermission"),
window: _("askForWindowPermission"),
domRect: _("askForDOMRectPermission")
domRect: _("askForDOMRectPermission"),
svg: _("askForSVGPermission"),
},
askStatus: {
alreadyAsked: {},
@ -103,7 +104,8 @@
audio: _("askForAudioInputPermission"),
history: _("askForHistoryInputPermission"),
window: _("askForWindowInputPermission"),
domRect: _("askForDOMRectInputPermission")
domRect: _("askForDOMRectInputPermission"),
svg: _("askForSVGInputPermission"),
},
askStatus: {
alreadyAsked: {},
@ -118,7 +120,8 @@
audio: _("askForAudioReadoutPermission"),
history: _("askForHistoryReadoutPermission"),
window: _("askForWindowReadoutPermission"),
domRect: _("askForDOMRectReadoutPermission")
domRect: _("askForDOMRectReadoutPermission"),
svg: _("askForSVGReadoutPermission"),
},
askStatus: {
alreadyAsked: {},

View File

@ -52,7 +52,7 @@
logging.message("check url %s for block mode %s", url, blockMode);
switch (url.protocol){
case "about:":
if (url.href === "about:blank"){
if (url.pathname === "blank"){
logging.message("use regular mode on about:blank");
break;
}

View File

@ -47,7 +47,10 @@
scope.init = function(){
function listener(details){
const headers = details.responseHeaders;
if (settings.get("blockDataURLs", new URL(details.url))){
if (
details.statusCode !== 304 &&
settings.get("blockDataURLs", new URL(details.url))
){
const cspMatch = (blockBlob? "": "blob: ") + "filesystem: *";
logging.verbose("Adding CSP header to", details);
setHeader(headers, {

View File

@ -72,7 +72,11 @@
return container;
};
scope.extensionID = browserAvailable? browser.extension.getURL(""): "extensionID";
scope.getURL = function getURL(str){
return browser.runtime.getURL(str);
};
scope.extensionID = browserAvailable? scope.getURL(""): "extensionID";
scope.inIncognitoContext = browserAvailable? browser.extension.inIncognitoContext: false;
@ -95,7 +99,8 @@
};
scope.exportFunctionWithName = function exportFunctionWithName(func, context, name){
const exportedTry = exportFunction(func, context, {allowCrossOriginArguments: true});
const targetObject = scope.getWrapped(context).Object.create(null);
const exportedTry = exportFunction(func, targetObject, {allowCrossOriginArguments: true, defineAs: name});
if (exportedTry.name === name){
return exportedTry;
}
@ -135,6 +140,113 @@
}
};
const proxies = new Map();
const changedWindowsForProxies = new WeakMap();
function setupWindowForProxies(window){
if (changedWindowsForProxies.get(window)){
return;
}
const wrappedWindow = scope.getWrapped(window);
const functionPrototype = wrappedWindow.Function.prototype;
const originalToString = functionPrototype.toString;
changedWindowsForProxies.set(window, originalToString);
const alteredToString = scope.createProxyFunction(
window,
originalToString,
function toString(){
if (proxies.has(this)){
return proxies.get(this).string;
}
return originalToString.call(scope.getWrapped(this));
}
);
scope.changeProperty(window, "toString", {
object: functionPrototype,
name: "toString",
type: "value",
changed: alteredToString
});
const wrappedReflect = wrappedWindow.Reflect;
const originalReflectSetPrototypeOf = wrappedReflect.setPrototypeOf;
const alteredReflectSetPrototypeOf = scope.exportFunctionWithName(
function setPrototypeOf(target, prototype){
target = scope.getWrapped(target);
if (proxies.has(target)){
target = proxies.get(target).wrappedOriginal;
}
if (proxies.has(prototype)){
prototype = proxies.get(prototype).wrappedOriginal;
}
if (prototype){
const grandPrototype = wrappedReflect.getPrototypeOf(prototype);
if (proxies.has(grandPrototype)){
const testPrototype = wrappedWindow.Object.create(proxies.get(grandPrototype).wrappedOriginal);
const value = originalReflectSetPrototypeOf.call(wrappedReflect, target, testPrototype);
if (!value){
return false;
}
}
}
const value = originalReflectSetPrototypeOf.call(wrappedReflect, target, scope.getWrapped(prototype));
return value;
}, window, "setPrototypeOf"
);
scope.changeProperty(window, "toString", {
object: wrappedWindow.Reflect,
name: "setPrototypeOf",
type: "value",
changed: alteredReflectSetPrototypeOf
});
}
scope.createProxyFunction = function createProxyFunction(window, original, replacement){
setupWindowForProxies(window);
const wrappedObject = scope.getWrapped(window).Object;
const handler = wrappedObject.create(null);
handler.apply = scope.exportFunctionWithName(function(target, thisArg, args){
try {
return args.length?
replacement.call(thisArg, ...args):
replacement.call(thisArg);
}
catch (error){
try {
return original.apply(thisArg, args);
}
catch (error){
return scope.getWrapped(target).apply(thisArg, args);
}
}
}, window, "");
handler.setPrototypeOf = scope.exportFunctionWithName(function(target, prototype){
target = scope.getWrapped(target);
if (proxies.has(target)){
target = proxies.get(target).wrappedOriginal;
}
if (proxies.has(prototype)){
prototype = proxies.get(prototype).wrappedOriginal;
}
if (prototype){
const grandPrototype = wrappedObject.getPrototypeOf(prototype);
if (proxies.has(grandPrototype)){
const testPrototype = wrappedObject.create(proxies.get(grandPrototype).wrappedOriginal);
wrappedObject.setPrototypeOf(target, testPrototype);
}
}
return wrappedObject.setPrototypeOf(target, scope.getWrapped(prototype));
}, window, "");
const proxy = new window.Proxy(original, handler);
const proxyData = {
original: original,
wrappedOriginal: scope.getWrapped(original),
string: changedWindowsForProxies.get(window).call(original),
};
proxies.set(proxy, proxyData);
proxies.set(scope.getWrapped(proxy), proxyData);
return scope.getWrapped(proxy);
};
const changedPropertiesByWindow = new WeakMap();
scope.changeProperty = function(window, group, {object, name, type, changed}){
let changedProperties = changedPropertiesByWindow.get(scope.getWrapped(window));
@ -189,5 +301,30 @@
}
};
scope.displayVersion = async function displayVersion(node, displayRefresh = false){
if ("string" === typeof node){
node = document.getElementById(node);
}
if (!node){
throw "display node not found";
}
fetch(scope.getURL("manifest.json")).then(function(response){
return response.json();
}).then(function(manifest){
node.textContent = "Version " + manifest.version;
return manifest.version;
}).catch(function(error){
node.textContent = "Unable to get version: " + error;
});
if (displayRefresh){
// Workaround to hide the scroll bars
window.setTimeout(function(){
node.style.display = "none";
node.style.display = "";
}, displayRefresh);
}
};
Object.seal(scope);
}());

View File

@ -205,7 +205,10 @@
logging.message("register listener for messages from background script");
extension.message.on(function(data){
if (data["canvasBlocker-unload"]){
extension.revertProperties();
extension.revertProperties(window);
for (let frameIndex = 0; frameIndex < window.length; frameIndex += 1){
extension.revertProperties(window[frameIndex]);
}
enabled = false;
}
if (

View File

@ -25,7 +25,7 @@
const descriptor = Object.getOwnPropertyDescriptor(object, name);
const original = descriptor[type];
if ((typeof changed) === "function"){
changed = extension.exportFunctionWithName(changed, window, original.name);
changed = extension.createProxyFunction(window, original, changed);
}
extension.changeProperty(window, "iframeProtection", {object, name, type, changed});
}
@ -41,6 +41,9 @@
return false;
}
}
window.addEventListener("unload", function(){
extension.revertProperties(window, "iframeProtection");
});
return changeProperty;
}

View File

@ -39,6 +39,9 @@
settings.on("rng", function(){
setRandomSupplyByType(settings.rng);
});
if (!settings.isStillDefault){
setRandomSupplyByType(settings.rng);
}
function getURL(windowToProcess){
let href;
@ -84,6 +87,9 @@
const forEachFunction = function(windowToProcess, callback){
apiNames.forEach(function(name){
const changedFunction = changedFunctions[name];
if (changedFunction.name){
name = changedFunction.name;
}
getAllFunctionObjects(windowToProcess, changedFunction).forEach(function(object){
if (object){
callback({name, object: object, changedFunction});
@ -234,7 +240,7 @@
name, changedFunction, siteStatus, original,
window: windowToProcess, prefs, notify, checkStack, ask
}){
return function checker(callingDepth = 2){
return function checker(callingDepth = 3){
const errorStack = (new Error()).stack;
try {
@ -317,6 +323,9 @@
function interceptFunctions(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
apiNames.forEach(function(name){
const changedFunction = changedFunctions[name];
if (changedFunction.name){
name = changedFunction.name;
}
const functionStatus = changedFunction.getStatus(undefined, siteStatus, prefs);
logging.verbose("status for", name, ":", functionStatus);
if (!functionStatus.active) return;
@ -335,24 +344,28 @@
let changed;
if (type ==="value"){
if (changedFunction.fakeGenerator){
changed = extension.exportFunctionWithName(
changedFunction.fakeGenerator(checker, original, windowToProcess),
windowToProcess,
original.name
);
if ((changedFunction.exportOptions || {}).allowCallbacks){
changed = extension.exportFunctionWithName(
changedFunction.fakeGenerator(checker, original, windowToProcess),
windowToProcess,
original.name
);
}
else {
const generated = changedFunction.fakeGenerator(checker, original, windowToProcess);
changed = extension.createProxyFunction(windowToProcess, original, generated);
}
}
else {
changed = null;
}
}
else {
changed = extension.exportFunctionWithName(function(){
return extension.exportFunctionWithName(
changedFunction.fakeGenerator(checker),
windowToProcess,
original.name
);
}, windowToProcess, descriptor.get.name);
changed = extension.createProxyFunction(windowToProcess, original, extension.exportFunctionWithName(
changedFunction.fakeGenerator(checker),
windowToProcess,
original.name
));
}
extension.changeProperty(windowToProcess, changedFunction.api, {
object, name, type, changed
@ -384,7 +397,7 @@
extension.changeProperty(windowToProcess, changedGetter.api,
{
object, name, type: "get",
changed: extension.exportFunctionWithName(getter, windowToProcess, original.name)
changed: extension.createProxyFunction(windowToProcess, original, getter)
}
);
@ -398,7 +411,7 @@
extension.changeProperty(windowToProcess, changedGetter.api,
{
object, name, type: "set",
changed: extension.exportFunctionWithName(setter, windowToProcess, original.name)
changed: extension.createProxyFunction(windowToProcess, original, setter)
}
);
}

View File

@ -15,6 +15,7 @@
}
const settings = require("./settings");
const logging = require("./logging");
function getDomainRegExpList(domainList){
@ -28,14 +29,27 @@
})
.map(function(entry){
let regExp;
const domain = !!entry.match(/^[A-Za-z0-9_.-]+$/);
const domain = !!entry.match(/^[A-Za-z0-9_.*-]+$/);
if (domain){
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$", "i");
regExp = new RegExp(
"(?:^|\\.)" + entry.replace(/([\\+?[^\]$(){}=!|.])/g, "\\$1").replace(/\*/g, ".+") + "\\.?$",
"i"
);
}
else {
regExp = new RegExp(entry, "i");
try {
regExp = new RegExp(entry, "i");
}
catch (error){
logging.error("Error in regular expression", entry, error);
regExp = new RegExp(
"(?:^|\\.)" + entry.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$",
"i"
);
}
}
return {
value: entry,
match: function(url){
if (domain){
return (url.hostname || "").match(regExp);
@ -119,9 +133,23 @@
await settings.set(type + "List", oldValue + (oldValue? ",": "") + entry);
return updateList(type);
};
scope.removeFrom = async function removeFromList(type, entry){
const oldValue = settings[type + "List"];
const filter = entry.forEach? v => entry.indexOf(v) === -1: v => v !== entry;
await settings.set(
type + "List",
oldValue
.split(",")
.map(v => v.replace(/^\s+|\s+$/, ""))
.filter(filter)
.join(",")
);
return updateList(type);
};
scope.update = updateList;
scope.updateAll = function updateAllLists(){
updateList("white");
updateList("sessionWhite");
updateList("ignore");
updateList("black");
updateStackList(settings.stackList);

View File

@ -78,10 +78,10 @@
}
}
function error (...args){performLog(1, args);}
function warning(...args){performLog(25, args);}
function message(...args){performLog(50, args);}
function notice (...args){performLog(75, args);}
function error (...args){performLog(1, args);}
function warning(...args){performLog(25, args);}
function message(...args){performLog(50, args);}
function notice (...args){performLog(75, args);}
function verbose(...args){performLog(100, args);}
function metaLog(...args){performLog(999, args);}

View File

@ -10,6 +10,7 @@
const persistentRndStorage = require("./persistentRndStorage");
const notification = require("./notification");
const mobile = require("./mobile");
const extension = require("./extension");
const registerSettingsContentScript = (function(){
let unregisterSettingsContentScript = function(){};
@ -90,7 +91,7 @@
}
}
if (data["canvasBlocker-clear-domain-rnd"]){
persistentRndStorage.clear();
persistentRndStorage.clear(data["canvasBlocker-clear-domain-rnd"] === "force");
if (keys.length === 1){
return;
}
@ -120,7 +121,7 @@
logging.verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd);
port.postMessage({
tabId: port.sender.tab.id,
cookieStoreId: port.sender.tab.cookieStoreId,
cookieStoreId: port.sender.tab.cookieStoreId || "",
persistentRnd: persistentRndStorage.persistentRnd,
persistentIncognitoRnd: persistentRndStorage.persistentIncognitoRnd
});
@ -161,7 +162,7 @@
!browser.pageAction.openPopup
){
browser.tabs.create({
url: browser.extension.getURL("options/options.html?notice=" + reason)
url: extension.getURL("options/options.html?notice=" + reason)
});
}
}
@ -169,8 +170,12 @@
case "install":
logging.message("CanvasBlocker installed");
openOptions(details.reason);
browser.tabs.create({
url: browser.extension.getURL("options/presets.html?notice=" + details.reason)
settings.onloaded(function(){
if (settings.showPresetsOnInstallation){
browser.tabs.create({
url: extension.getURL("options/presets.html?notice=" + details.reason)
});
}
});
break;
case "update":
@ -199,5 +204,29 @@
});
});
}
if (browser.runtime.onUpdateAvailable){
browser.runtime.onUpdateAvailable.addListener(async function(details){
logging.message("Update available", details);
if (settings.disruptSessionOnUpdate){
await Promise.all((await browser.tabs.query({})).map(async function(tab){
try{
await browser.tabs.sendMessage(tab.id, {
"canvasBlocker-unload": true
});
}
catch(error){
logging.verbose("error while unloading", tab, ":", error);
}
}));
window.setTimeout(function(){
logging.verbose("Reload extension after one second");
browser.runtime.reload();
}, 1000);
}
else {
settings.updatePending = true;
}
});
}
logging.message("end");
}());

View File

@ -16,6 +16,10 @@
const settingDefinitions = require("./settingDefinitions");
scope.isMobile = async function isMobile(){
const platformInfo = await browser.runtime.getPlatformInfo();
if (platformInfo && platformInfo.os === "android"){
return true;
}
// todo: proper mobile check (e.g. over browser.runtime.getBrowserInfo()) and no feature check
return !browser.pageAction ||
!browser.pageAction.show ||

View File

@ -39,6 +39,8 @@
appendModified(require("./modifiedHistoryAPI"));
appendModified(require("./modifiedWindowAPI"));
appendModified(require("./modifiedDOMRectAPI"));
appendModified(require("./modifiedSVGAPI"));
appendModified(require("./modifiedTextMetricsAPI"));
appendModified(require("./modifiedNavigatorAPI"));
appendModified(require("./modifiedScreenAPI"));
}());

View File

@ -226,17 +226,27 @@
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
notify("fakedInput");
let oldImageData;
let x, y, width, height;
const getImageData = window.CanvasRenderingContext2D.prototype.getImageData;
const border = 4;
try {
// "this" is not trustable - it may be not a context
oldImageData = getImageData(window, this).imageData;
const measurement = window.CanvasRenderingContext2D.prototype.measureText.call(this, args[0]);
const left = Math.max(0, measurement.actualBoundingBoxLeft);
const top = Math.max(0, measurement.actualBoundingBoxAscent);
width = Math.ceil(measurement.actualBoundingBoxRight + left) + 2 * border;
height = Math.ceil(measurement.actualBoundingBoxDescent + top) + 2 * border;
x = args[1] - border - left;
y = args[2] - border - top;
oldImageData = getImageData.call(this, x, y, width, height);
}
catch (error){
// nothing to do here
}
// if "this" is not a correct context the next line will throw an error
const ret = original.call(this, ...args);
const newImageData = getImageData(window, this).imageData;
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
const newImageData = getImageData.call(this, x, y, width, height);
this.putImageData(randomMixImageData(window, oldImageData, newImageData), x, y);
return ret;
}
else {
@ -244,6 +254,62 @@
}
}
function offscreenToBlobCallback(args, check){
const {prefs, notify, window, original} = check;
if (canvasSizeShouldBeFaked(this, prefs)){
try {
const canvas = window.document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
const context = canvas.getContext("2d");
context.drawImage(this.transferToImageBitmap(), 0, 0);
const fakeCanvas = getFakeCanvas(window, canvas, prefs);
if (fakeCanvas !== canvas){
notify("fakedReadout");
}
const fakeContext = getContext(window, fakeCanvas);
const {imageData} = getImageData(window, fakeContext);
const fakeOffscreenCanvas = new window.OffscreenCanvas(this.width, this.height);
const offscreenContext = fakeOffscreenCanvas.getContext("2d");
offscreenContext.putImageData(imageData, 0, 0);
return original.call(fakeOffscreenCanvas, ...args);
}
catch (error){
logging.warning("Error while faking:", error);
return original.call(this, ...args);
}
}
else {
return original.call(this, ...args);
}
}
const isPointCache = Object.create(null);
function getIsPointCacheIndex(x, y, values){
return String.fromCodePoint(...values, x, y);
}
function getIsPointValue({func, x, y, index, originalValue, window, prefs}){
const useCanvasCache = prefs("useCanvasCache");
let cacheIndex;
const values = [originalValue, func(x^1, y), func(x, y^1), func(x^1, y^1)];
if (useCanvasCache){
cacheIndex = getIsPointCacheIndex(x, y, values);
const cached = isPointCache[cacheIndex];
if ((typeof cached) === "boolean"){
return cached;
}
}
const rng = randomSupply.getIndexRng(1, 4, window);
const res = values[rng(index)];
if (useCanvasCache){
isPointCache[cacheIndex] = res;
}
return res;
}
// changed functions and their fakes
scope.changedFunctions = {
getContext: {
@ -271,7 +337,7 @@
},
object: "HTMLCanvasElement",
fakeGenerator: function(checker){
return function(context, contextAttributes){
return function getContext(context, contextAttributes){
return checkerWrapper(checker, this, arguments, function(args, check){
const {original} = check;
canvasContextType.set(this, context);
@ -296,6 +362,11 @@
object: "HTMLCanvasElement",
fakeGenerator: function(checker){
return function toBlob(callback){
if (this instanceof toBlob){
throw new extension.getWrapped(window).TypeError(
"HTMLCanvasElement.prototype.toBlob is not a constructor"
);
}
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
};
},
@ -309,7 +380,8 @@
return function mozGetAsFile(callback){
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
};
}
},
exportOptions: {allowCallbacks: true}
},
getImageData: {
type: "readout",
@ -348,13 +420,16 @@
fakeGenerator: function(checker){
return function isPointInPath(x, y){
return checkerWrapper(checker, this, arguments, function(args, check){
const {notify, window, original} = check;
const rng = randomSupply.getValueRng(1, window);
const {prefs, notify, window, original} = check;
const originalValue = original.call(this, ...args);
if ((typeof originalValue) === "boolean"){
notify("fakedReadout");
const index = x + this.width * y;
return original.call(this, rng(x, index), rng(y, index), args[2]);
return getIsPointValue({
func: (x, y) => original.call(this, x, y, args[2]),
x, y,
index: x + this.canvas.width * y,
originalValue, window, prefs
});
}
else {
return originalValue;
@ -370,22 +445,26 @@
fakeGenerator: function(checker){
return function isPointInStroke(x, y){
return checkerWrapper(checker, this, arguments, function(args, check){
const {notify, window, original} = check;
const rng = randomSupply.getValueRng(1, window);
const {prefs, notify, window, original} = check;
const originalValue = original.call(this, ...args);
if ((typeof originalValue) === "boolean"){
notify("fakedReadout");
let func;
if (x instanceof window.Path2D){
let path = x;
x = y;
y = args[2];
let index = x + this.width * y;
return original.call(this, path, rng(x, index), rng(y, index));
func = (x, y) => original.call(this, path, x, y);
}
else {
let index = x + this.width * y;
return original.call(this, rng(x, index), rng(y, index));
func = (x, y) => original.call(this, x, y);
}
return getIsPointValue({
func,
x, y,
index: x + this.canvas.width * y,
originalValue, window, prefs
});
}
else {
return originalValue;
@ -464,7 +543,70 @@
});
};
}
}
},
getExtension: {
type: "readout",
getStatus: createGetStatus(["readout", "input"]),
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
fakeGenerator: function(checker){
return function getExtension(extensionName){
return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check;
const originalValue = original.call(this, ...args);
if (
extensionName === "WEBGL_debug_renderer_info" &&
originalValue &&
webgl.parameterChangeDefinition[originalValue.UNMASKED_VENDOR_WEBGL] &&
webgl.parameterChangeDefinition[originalValue.UNMASKED_RENDERER_WEBGL]
){
const {value: vendorValue, faked: vendorFaked} = webgl
.parameterChangeDefinition[originalValue.UNMASKED_VENDOR_WEBGL]
.fake(this.getParameter(originalValue.UNMASKED_VENDOR_WEBGL), window, prefs);
const {value: rendererValue, faked: rendererFaked} = webgl
.parameterChangeDefinition[originalValue.UNMASKED_RENDERER_WEBGL]
.fake(this.getParameter(originalValue.UNMASKED_RENDERER_WEBGL), window, prefs);
if (
vendorFaked && vendorValue === null &&
rendererFaked && rendererValue === null
){
const value = null;
if (originalValue !== value){
notify("fakedReadout");
}
return value;
}
else {
return originalValue;
}
}
else {
return originalValue;
}
});
};
}
},
convertToBlob: {
type: "readout",
getStatus: createGetStatus("readout"),
object: ["OffscreenCanvas"],
fakeGenerator: function(checker){
return function convertToBlob(){
return checkerWrapper(checker, this, arguments, offscreenToBlobCallback);
};
}
},
offscreenToBlob: {
name: "toBlob",
type: "readout",
getStatus: createGetStatus("readout"),
object: ["OffscreenCanvas"],
fakeGenerator: function(checker){
return function toBlob(){
return checkerWrapper(checker, this, arguments, offscreenToBlobCallback);
};
}
},
};
Object.keys(scope.changedFunctions).forEach(function(key){
scope.changedFunctions[key].api = "canvas";

View File

@ -50,43 +50,79 @@
}
const cache = {};
const valueCache = [{}, {}, {}, {}];
const valueCache = [{}, {}, {}, {}, {}, {}, {}];
scope.cache = {
valueCache,
X: 0,
Y: 1,
WIDTH: 2,
HEIGHT: 3,
OTHER: 4,
Z: 5,
W: 6,
};
function getFakeValue(value, i, {window, prefs, rng}){
const valueHash = getValueHash(value);
const cache = valueCache[i];
let cachedValue = cache[valueHash];
if (typeof cachedValue === "number"){
return cachedValue;
}
if ((value * prefs("domRectIntegerFactor", window.location)) % 1 === 0){
cache[valueHash] = value;
return value;
}
else {
const fakedValue = value + 0.01 * (rng(i) / 0xffffffff - 0.5);
const fakedHash = getValueHash(fakedValue);
cache[valueHash] = fakedValue;
cache[fakedHash] = fakedValue;
return fakedValue;
}
}
scope.getFakeValue = getFakeValue;
function getFakeDomRect(window, domRect, prefs, notify){
const hash = getHash(domRect);
let cached = cache[hash];
if (!cached){
notify("fakedDOMRectReadout");
const rng = randomSupply.getRng(4, window);
const getFakeValue = function getFakeValue(value, i){
const valueHash = getValueHash(value);
const cache = valueCache[i];
let cachedValue = cache[valueHash];
if (typeof cachedValue === "number"){
return cachedValue;
}
if ((value * prefs("domRectIntegerFactor", window.location)) % 1 === 0){
cache[valueHash] = value;
return value;
}
else {
const fakedValue = value + 0.01 * (rng(i) / 0xffffffff - 0.5);
const fakedHash = getValueHash(fakedValue);
cache[valueHash] = fakedValue;
cache[fakedHash] = fakedValue;
return fakedValue;
}
};
cached = new domRect.constructor(
getFakeValue(domRect.x, 0),
getFakeValue(domRect.y, 1),
getFakeValue(domRect.width, 2),
getFakeValue(domRect.height, 3)
const env = {window, prefs, rng};
cached = new (domRect instanceof window.SVGRect? window.DOMRectReadOnly: domRect.constructor)(
getFakeValue(domRect.x, 0, env),
getFakeValue(domRect.y, 1, env),
getFakeValue(domRect.width, 2, env),
getFakeValue(domRect.height, 3, env)
);
cache[hash] = cached;
cache[getHash(cached)] = cached;
}
return cached;
}
function getFakeDOMPoint(window, domPoint, prefs){
const env = {window, prefs, rng: randomSupply.getRng(7, window)};
return new domPoint.constructor(
getFakeValue(domPoint.x, 0, env),
getFakeValue(domPoint.y, 1, env),
getFakeValue(domPoint.z, 5, env),
getFakeValue(domPoint.w, 6, env)
);
}
function getFakeSVGPoint(window, svgPoint, prefs){
const env = {window, prefs, rng: randomSupply.getRng(2, window)};
svgPoint.x = getFakeValue(svgPoint.x, 0, env);
svgPoint.y = getFakeValue(svgPoint.y, 1, env);
return svgPoint;
}
function getFakeDOMQuad(window, domQuad, prefs, notify){
notify("fakedDOMRectReadout");
return new domQuad.constructor(
getFakeDOMPoint(window, domQuad.p1, prefs),
getFakeDOMPoint(window, domQuad.p2, prefs),
getFakeDOMPoint(window, domQuad.p3, prefs),
getFakeDOMPoint(window, domQuad.p4, prefs)
);
}
function registerCallback(args, check){
const {prefs, notify, window, original} = check;
@ -97,6 +133,18 @@
return originalValue;
}
function fakePointCallback(args, check){
const {prefs, notify, window, original} = check;
const ret = args.length? original.call(this, ...args): original.call(this);
notify("fakedDOMRectReadout");
if (ret instanceof window.SVGPoint){
return getFakeSVGPoint(window, ret, prefs);
}
else {
return getFakeDOMPoint(window, ret, prefs);
}
}
scope.changedFunctions = {
getClientRects: {
object: ["Range", "Element"],
@ -122,14 +170,31 @@
}
},
getBounds: {
object: ["DOMQuad"],
getBoxQuads: {
object: ["Document", "Element", "Text", "CSSPseudoElement"],
fakeGenerator: function(checker){
return function getBounds(){
return checkerWrapper(checker, this, arguments, registerCallback);
return function getBoxQuads(){
return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check;
const ret = args.length? original.call(this, ...args): original.call(this);
for (let i = 0; i < ret.length; i += 1){
ret[i] = getFakeDOMQuad(window, ret[i], prefs, notify);
}
return ret;
});
};
}
},
// It seems only getBoxQuads creates a DOMQuad and this method is behind a flag.
// So the only way to create one is manually by the constructor and then no fingerprinting is possible.
// getBounds: {
// object: ["DOMQuad"],
// fakeGenerator: function(checker){
// return function getBounds(){
// return checkerWrapper(checker, this, arguments, registerCallback);
// };
// }
// },
getBBox: {
object: ["SVGGraphicsElement"],
fakeGenerator: function(checker){
@ -138,6 +203,23 @@
};
}
},
getStartPositionOfChar: {
object: ["SVGTextContentElement"],
fakeGenerator: function(checker){
return function getStartOfChar(){
return checkerWrapper(checker, this, arguments, fakePointCallback);
};
}
},
getEndPositionOfChar: {
object: ["SVGTextContentElement"],
fakeGenerator: function(checker){
return function getEndOfChar(){
return checkerWrapper(checker, this, arguments, fakePointCallback);
};
}
},
getExtentOfChar: {
object: ["SVGTextContentElement"],
fakeGenerator: function(checker){
@ -146,6 +228,14 @@
};
}
},
getPointAtLength: {
object: ["SVGGeometryElement", "SVGPathElement"],
fakeGenerator: function(checker){
return function getPointAtLength(){
return checkerWrapper(checker, this, arguments, fakePointCallback);
};
}
},
};
function generateChangedDOMRectPropertyGetter(property, readonly = false){
@ -156,6 +246,7 @@
]:
[
function(window){return window.DOMRect && window.DOMRect.prototype;},
function(window){return window.SVGRect && window.SVGRect.prototype;},
function(window){return window.DOMRectReadOnly && window.DOMRectReadOnly.prototype;}
],
name: property,

View File

@ -12,7 +12,7 @@
scope = require.register("./modifiedNavigatorAPI", {});
}
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const extension = require("./extension");
const navigator = require("./navigator");
@ -55,7 +55,40 @@
};
});
setGetterProperties(scope.changedGetters, {
scope.changedFunctions = {
estimate: {
objectGetters: [function(window){return window.StorageManager && window.StorageManager.prototype;}],
fakeGenerator: function(checker){
const quota = 10 * 1024 * 1024 * 1024;
return function estimate(){
return checkerWrapper(checker, this, arguments, function(args, check){
const {notify, original, window} = check;
const This = this;
return new window.Promise(async function(resolve, reject){
try {
const originalValue = await original.call(This, ...args);
if (originalValue.quota !== quota){
originalValue.usage = Math.min(
quota,
Math.max(0, quota - (originalValue.quota - originalValue.usage))
);
originalValue.quota = quota;
notify("fakedNavigatorReadout");
}
resolve(originalValue);
}
catch (error){
reject(error);
}
});
});
};
}
}
};
setProperties(scope.changedFunctions, scope.changedGetters, {
type: "readout",
getStatus: getStatusByFlag("protectNavigator"),
api: "navigator"

88
lib/modifiedSVGAPI.js Normal file
View File

@ -0,0 +1,88 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
let scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
scope = require.register("./modifiedSVGAPI", {});
}
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const {byteArrayToString: hash} = require("./hash");
let randomSupply = null;
scope.setRandomSupply = function(supply){
randomSupply = supply;
};
function getValueHash(value){
return hash(new Float32Array([value]));
}
const cache = {};
function getFakeValue(value, window){
const valueHash = getValueHash(value);
let cachedValue = cache[valueHash];
if (typeof cachedValue === "number"){
return cachedValue;
}
else {
const rng = randomSupply.getRng(1, window);
const fakedValue = value + 0.01 * (rng(0) / 0xffffffff - 0.5);
const fakedHash = getValueHash(fakedValue);
cache[valueHash] = fakedValue;
cache[fakedHash] = fakedValue;
return fakedValue;
}
}
scope.getFakeValue = getFakeValue;
function getFakeValueCallback(args, check){
const {notify, window, original} = check;
const ret = args.length? original.call(this, ...args): original.call(this);
notify("fakedSVGReadout");
return getFakeValue(ret, window);
}
scope.changedFunctions = {
getTotalLength: {
object: ["SVGGeometryElement"],
fakeGenerator: function(checker){
return function getTotalLength(){
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
};
}
},
getComputedTextLength: {
object: ["SVGTextContentElement"],
fakeGenerator: function(checker){
return function getComputedTextLength(){
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
};
}
},
getSubStringLength: {
object: ["SVGTextContentElement"],
fakeGenerator: function(checker){
return function getSubStringLength(charnum, nchars){
return checkerWrapper(checker, this, arguments, getFakeValueCallback);
};
}
},
};
scope.changedGetters = [];
setProperties(scope.changedFunctions, scope.changedGetters, {
type: "readout",
getStatus: getStatusByFlag("protectSVG"),
api: "svg"
});
}());

View File

@ -184,7 +184,7 @@
getterGenerator: function(checker){
const temp = {
get outerWidth(){
return checkerWrapper(checker, this, arguments, getFaker(window => window.innerWidth));
return checkerWrapper(checker, this, arguments, getFaker(window => window.top.innerWidth));
}
};
return Object.getOwnPropertyDescriptor(temp, "outerWidth").get;
@ -196,7 +196,7 @@
getterGenerator: function(checker){
const temp = {
get outerHeight(){
return checkerWrapper(checker, this, arguments, getFaker(window => window.innerHeight));
return checkerWrapper(checker, this, arguments, getFaker(window => window.top.innerHeight));
}
};
return Object.getOwnPropertyDescriptor(temp, "outerHeight").get;
@ -212,7 +212,7 @@
/\(\s*(?:(min|max)-)?device-(width|height):\s+(\d+\.?\d*)px\s*\)/,
function(m, type, dimension, value){
value = parseFloat(value);
let newCompareValue = value;
let newCompareValue;
switch (type){
case "min":
if (value <= dimensions[dimension]){

View File

@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
let scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
scope = require.register("./modifiedTextMetricsAPI", {});
}
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
const {byteArrayToString: hash} = require("./hash");
const {cache} = require("./modifiedDOMRectAPI");
const valueCache = cache.valueCache;
function getValueHash(value){
return hash(new Float32Array([value]));
}
let randomSupply = null;
scope.setRandomSupply = function(supply){
randomSupply = supply;
};
function getFakeValue(window, value, i, prefs){
const valueHash = getValueHash(value);
const cache = valueCache[i];
let cachedValue = cache[valueHash];
if (typeof cachedValue === "number"){
return cachedValue;
}
if ((value * prefs("domRectIntegerFactor", window.location)) % 1 === 0){
cache[valueHash] = value;
return value;
}
else {
const rng = randomSupply.getRng(5, window);
const fakedValue = value + 0.01 * (rng(i) / 0xffffffff - 0.5);
const fakedHash = getValueHash(fakedValue);
cache[valueHash] = fakedValue;
cache[fakedHash] = fakedValue;
return fakedValue;
}
}
function generateChangedTextMetricsPropertyGetter(property, cacheIndex){
const changedGetter = {
objectGetters: [
function(window){return window.TextMetrics && window.TextMetrics.prototype;}
],
name: property,
getterGenerator: function(checker){
const temp = {
get [property](){
return checkerWrapper(checker, this, arguments, function(args, check){
const {prefs, notify, window, original} = check;
const originalValue = original.call(this, ...args);
const returnValue = getFakeValue(window, originalValue, cacheIndex, prefs);
if (originalValue !== returnValue){
notify("fakedTextMetricsReadout");
}
return returnValue;
});
}
};
return Object.getOwnPropertyDescriptor(temp, property).get;
}
};
return changedGetter;
}
scope.changedGetters = [
generateChangedTextMetricsPropertyGetter("width", cache.WIDTH),
generateChangedTextMetricsPropertyGetter("actualBoundingBoxAscent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("actualBoundingBoxDescent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("actualBoundingBoxLeft", cache.OTHER),
generateChangedTextMetricsPropertyGetter("actualBoundingBoxRight", cache.OTHER),
generateChangedTextMetricsPropertyGetter("alphabeticBaseline", cache.OTHER),
generateChangedTextMetricsPropertyGetter("emHeightAscent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("emHeightDescent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("fontBoundingBoxAscent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("fontBoundingBoxDescent", cache.OTHER),
generateChangedTextMetricsPropertyGetter("hangingBaseline", cache.OTHER),
generateChangedTextMetricsPropertyGetter("ideographicBaseline", cache.OTHER),
];
setProperties({}, scope.changedGetters, {
type: "readout",
getStatus: getStatusByFlag("protectTextMetrics"),
api: "textMetrics"
});
}());

View File

@ -26,6 +26,7 @@
original[property] = window.navigator[property];
});
original["real Firefox version"] = window.navigator.userAgent.replace(/^.+Firefox\//, "");
original["real Firefox version - rv"] = window.navigator.userAgent.replace(/^.+; rv:([\d.]+).*$/, "$1");
let changedValues = {};

View File

@ -89,19 +89,10 @@
};
}();
browser.windows.onRemoved.addListener(async function(){
const windows = await browser.windows.getAll();
if (windows.every(function(window){
return !window.incognito;
})){
clearIncognito();
}
});
function registerTimeout(){
const interval = getInterval();
if (interval > 0){
const timeout = settings.lastPersistentRndClearing + interval - Date.now();
const timeout = settings.lastPersistentRndClearing + interval - Date.now();
logging.message("registering persistent rng data clearing timeout. Clearing in ", timeout, "ms");
if (timeout > 1073741824){
// window.setTimeout can only handle delays up to 32 bit.
@ -123,14 +114,14 @@
scope.persistentIncognitoRnd = Object.create(null);
settings.persistentIncognitoRndStorage = JSON.stringify(scope.persistentIncognitoRnd);
}
function clear(){
function clear(force = false){
logging.verbose("domain rnd cleared");
scope.persistentRnd = Object.create(null);
settings.persistentRndStorage = JSON.stringify(scope.persistentRnd);
settings.lastPersistentRndClearing = Date.now();
clearIncognito();
registerTimeout();
broadcast({"canvasBlocker-clear-domain-rnd": true});
broadcast({"canvasBlocker-clear-domain-rnd": force? "force": true});
}
function setDomainData(domain, incognito, rnd){
logging.verbose("got new domain rnd for ", domain, " (incognito:", incognito, "):", rnd);
@ -173,4 +164,18 @@
scope.setDomainData = setDomainData;
scope.clearDomainData = clearDomainData;
scope.clearContainerData = clearContainerData;
try {
browser.windows.onRemoved.addListener(async function(){
const windows = await browser.windows.getAll();
if (windows.every(function(window){
return !window.incognito;
})){
clearIncognito();
}
});
}
catch (error){
logging.error("Unable to register windows.onRemoved listener", error);
}
}());

View File

@ -63,7 +63,6 @@
};
const settings = require("./settings");
const logging = require("./logging");
const extension = require("./extension");
function getDomain(window){
@ -83,6 +82,12 @@
let persistentRnd = Object.create(null);
let cookieStoreId = false;
function getCookieStoreId(){
while (cookieStoreId === false){
extension.waitSync("to wait for cookie store id");
}
return cookieStoreId;
}
settings.onloaded(function(){
try {
let storedData = JSON.parse(
@ -117,15 +122,24 @@
}
}
if (data["canvasBlocker-clear-domain-rnd"]){
const domain = getCookieStoreId() + getDomain(window);
let ownPersistendRnd = data["canvasBlocker-clear-domain-rnd"] !== "force"? persistentRnd[domain]: false;
persistentRnd = Object.create(null);
if (ownPersistendRnd){
persistentRnd[domain] = ownPersistendRnd;
extension.message.send({
"canvasBlocker-new-domain-rnd": {
domain,
incognito: extension.inIncognitoContext,
rnd: Array.from(persistentRnd[domain])
}
});
}
}
});
return function getPersistentRnd(window){
while (cookieStoreId === false){
extension.waitSync("to wait for cookie store id");
}
const domain = cookieStoreId + getDomain(window);
const domain = getCookieStoreId() + getDomain(window);
if (!persistentRnd[domain]){
// create the (sub-)domains random numbers if not existing
persistentRnd[domain] = new Uint8Array(128);

View File

@ -19,17 +19,26 @@
texts.push({text: text.toLowerCase(), content});
};
scope.search = function(search){
const resultSets = search.toLowerCase().split(/\s+/).filter(function(term){
const resultSets = search.split(/\s+/).filter(function(term){
return term.trim();
}).map(function(term){
return new RegExp(term);
}).map(function(term){
const matching = new Set();
texts.forEach(function(text){
if (term.test(text.text)){
matching.add(text.content);
}
});
if (term.match(/^:[a-z]+$/i)){
const tag = term.substring(1);
texts.forEach(function(text){
if (text.content.querySelector(`.${tag}`)){
matching.add(text.content);
}
});
}
else {
term = new RegExp(term.toLowerCase());
texts.forEach(function(text){
if (term.test(text.text)){
matching.add(text.content);
}
});
}
return matching;
});
if (resultSets.length){

View File

@ -40,6 +40,7 @@
let newEntry = {url};
newEntry[name] = value;
urlContainerValue.push(newEntry);
initializeUrlSetting(newEntry);
matching = [newEntry];
}
matching[0][name] = value;
@ -47,18 +48,17 @@
};
scope.resetUrlValue = function(name, url){
let urlContainerValue = scope.urlContainer.get();
const matching = urlContainerValue.filter(function(urlSetting){
urlContainerValue.filter(function(urlSetting){
return urlSetting.match(url);
});
if (matching.length){
delete matching[0][name];
if (Object.keys(matching[0]).every(function(key){return key === "url";})){
}).forEach(function(match){
delete match[name];
if (Object.keys(match).every(function(key){return key === "url";})){
urlContainerValue = urlContainerValue.filter(function(urlSetting){
return urlSetting !== matching[0];
return urlSetting !== match;
});
}
scope.urlContainer.set(urlContainerValue);
}
});
scope.urlContainer.set(urlContainerValue);
};
function processHideContainer(settingDefinition){
@ -164,51 +164,62 @@
}
};
function initializeUrlSetting(urlSetting){
let regExp;
const domain = !!urlSetting.url.match(/^[A-Za-z0-9_.*-]+$/);
if (domain){
regExp = new RegExp(
"(?:^|\\.)" + urlSetting.url.replace(/([\\+?[^\]$(){}=!|.])/g, "\\$1").replace(/\*/g, ".+") + "\\.?$",
"i"
);
}
else {
try {
regExp = new RegExp(urlSetting.url, "i");
}
catch (error){
logging.error("Error in regular expression", urlSetting.url, error);
regExp = new RegExp(
"(?:^|\\.)" + urlSetting.url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$",
"i"
);
}
}
const match = function(url){
if (!url){
return false;
}
else if (
url instanceof String ||
(typeof url) === "string"
){
return url === urlSetting.url;
}
else if (domain){
return (url.hostname || "").match(regExp);
}
else {
return url.href.match(regExp);
}
};
Object.defineProperty(
urlSetting,
"match",
{
enumerable: false,
writable: true,
configurable: true,
value: match
}
);
}
scope.initializeUrlContainer = function(eventHandler){
if (!scope.urlContainer){
return;
}
scope.urlContainer.on(function({newValue, oldValue}){
newValue.forEach(function(urlSetting){
let regExp;
const domain = !!urlSetting.url.match(/^[A-Za-z0-9_.-]+$/);
if (domain){
regExp = new RegExp(
"(?:^|\\.)" + urlSetting.url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$",
"i"
);
}
else {
regExp = new RegExp(urlSetting.url, "i");
}
const match = function(url){
if (!url){
return false;
}
else if (
url instanceof String ||
(typeof url) === "string"
){
return url === urlSetting.url;
}
else if (domain){
return (url.hostname || "").match(regExp);
}
else {
return url.href.match(regExp);
}
};
Object.defineProperty(
urlSetting,
"match",
{
enumerable: false,
writable: true,
configurable: true,
value: match
}
);
});
newValue.forEach(initializeUrlSetting);
const newUrls = newValue.map(function(entry){return entry.url;});
const oldUrls = oldValue.map(function(entry){return entry.url;});

View File

@ -93,12 +93,14 @@
{name: "Canvas-API", level: 1},
"getContext @ canvas",
{message: "readout", level: 2},
"toDataURL @ canvas", "toBlob @ canvas", "mozGetAsFile @ canvas", "getImageData @ canvas",
"toDataURL @ canvas",
"toBlob @ canvas", "convertToBlob @ canvas", "mozGetAsFile @ canvas",
"getImageData @ canvas",
"isPointInPath @ canvas", "isPointInStroke @ canvas",
{message: "input", level: 2},
"fillText @ canvas", "strokeText @ canvas",
{name: "webGL", level: 2},
"readPixels @ canvas", "getParameter @ canvas",
"readPixels @ canvas", "getParameter @ canvas", "getExtension @ canvas",
{name: "Audio-API", level: 1},
"getFloatFrequencyData @ audio", "getByteFrequencyData @ audio",
"getFloatTimeDomainData @ audio", "getByteTimeDomainData @ audio",
@ -112,17 +114,39 @@
{name: "DOMRect-API", level: 1},
"getClientRects @ domRect",
"getBoundingClientRect @ domRect",
"getBoxQuads @ domRect",
"getBounds @ domRect",
"getBBox @ domRect",
"getStartPositionOfChar @ domRect",
"getEndPositionOfChar @ domRect",
"getExtentOfChar @ domRect",
"getPointAtLength @ domRect",
"intersectionRect @ domRect",
"boundingClientRect @ domRect",
"rootBounds",
"rootBounds @ domRect",
{name: "SVG-API", level: 1},
"getTotalLength @ svg",
"getComputedTextLength @ svg",
"getSubStringLength @ svg",
{name: "TextMetrics-API", level: 1},
"width @ textMetrics",
"actualBoundingBoxAscent @ textMetrics",
"actualBoundingBoxDescent @ textMetrics",
"actualBoundingBoxLeft @ textMetrics",
"actualBoundingBoxRight @ textMetrics",
"alphabeticBaseline @ textMetrics",
"emHeightAscent @ textMetrics",
"emHeightDescent @ textMetrics",
"fontBoundingBoxAscent @ textMetrics",
"fontBoundingBoxDescent @ textMetrics",
"hangingBaseline @ textMetrics",
"ideographicBaseline @ textMetrics",
{name: "Navigator-API", level: 1},
"appCodeName @ navigator",
"appName @ navigator",
"appVersion @ navigator",
"buildID @ navigator",
"estimate @ navigator",
"oscpu @ navigator",
"platform @ navigator",
"product @ navigator",
@ -261,7 +285,10 @@
"history",
"window",
"domRect",
"svg",
"textMetrics",
"navigator",
"screen",
],
defaultKeyValue: false
},
@ -335,6 +362,16 @@
name: "domRectIntegerFactor",
defaultValue: 4
},
{
name: "protectSVG",
defaultValue: true,
urlSpecific: true
},
{
name: "protectTextMetrics",
defaultValue: true,
urlSpecific: true
},
{
name: "blockDataURLs",
defaultValue: true,
@ -378,10 +415,23 @@
defaultValue: "auto",
options: ["auto", "default", "light", "dark", "colorful"/*, "none"*/]
},
{
name: "showPresetsOnInstallation",
defaultValue: true
},
{
name: "dontShowOptionsOnUpdate",
defaultValue: false
},
{
name: "disruptSessionOnUpdate",
defaultValue: false
},
{
name: "updatePending",
resetOnStartup: true,
defaultValue: false
},
{
name: "isStillDefault",
defaultValue: true

View File

@ -13,9 +13,10 @@
}
const settings = require("./settings");
const extension = require("./extension");
scope.init = function(page){
const basePath = browser.extension.getURL("themes");
const basePath = extension.getURL("themes");
const baseLink = document.createElement("link");
baseLink.href = `${basePath}/base/layout.css`;

View File

@ -75,11 +75,11 @@
const positionAttributeLocation = context.getAttribLocation(program, "a_position");
context.enableVertexAttribArray(positionAttributeLocation);
const size = 2; // 2 components per iteration
const type = context.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
const offset = 0; // start at the beginning of the buffer
const size = 2; // 2 components per iteration
const type = context.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
const offset = 0; // start at the beginning of the buffer
context.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
const texCoordLocation = context.getAttribLocation(program, "a_texCoord");
@ -110,9 +110,11 @@
return {webGlCanvas, context};
};
const webglRandom = require("./webglRandom");
let randomSupply = null;
scope.setRandomSupply = function(supply){
randomSupply = supply;
webglRandom.setRandomSupply(supply);
};
function getNumber({originalValue, max, index, window}){
@ -129,6 +131,23 @@
const parameterFakeTypes = {
preference: function(originalValue, definition, window, prefs){
const settingValue = prefs(definition.preferenceName) || originalValue;
switch (settingValue){
case "{undefined}":
return undefined;
case "{false}":
return false;
case "{empty}":
return "";
case "{disabled}":
return null;
case "{random vendor}":
return webglRandom.getRandomVendor(window);
case "{random renderer}":
return webglRandom.getRandomRenderer(window);
}
if (settingValue.startsWith("<") && settingValue.endsWith(">")){
return webglRandom.pickOneFromTree(settingValue, window);
}
return settingValue;
},
decimal: function(originalValue, definition, window){
@ -199,8 +218,8 @@
scope.initializeParameterDefinitions = function(){
function singleFake(originalValue, window, prefs){
let value = parameterFakeTypes[this.type](originalValue, this, window, prefs);
let faked = value === originalValue;
const value = parameterFakeTypes[this.type](originalValue, this, window, prefs);
const faked = value !== originalValue;
this.fake = function(){
return {value, faked};
};
@ -211,7 +230,7 @@
let fakedValue = [];
for (let i = 0; i < originalValue.length; i += 1){
fakedValue[i] = parameterFakeTypes[this.type](originalValue[i], this, window, prefs);
faked |= originalValue[i] === fakedValue[i];
faked = faked || originalValue[i] !== fakedValue[i];
originalValue[i] = fakedValue[i];
}
this.fake = function(originalValue){

173
lib/webglRandom.js Normal file
View File

@ -0,0 +1,173 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
let scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
scope = require.register("./webglRandom", {});
}
let randomSupply = null;
scope.setRandomSupply = function(supply){
randomSupply = supply;
};
const windowHashes = new WeakMap();
function getWindowStorage(window){
let storage = windowHashes.get(window);
if (!storage){
const vendorRng = randomSupply.getIndexRng(1, scope.vendors.length, window);
const vendorIndex = vendorRng(0);
storage = {vendorIndex};
const vendor = scope.vendors[vendorIndex];
if (vendor.getRandomRenderer){
vendor.renderers = [vendor.getRandomRenderer(window)];
storage.rendererIndex = 0;
}
else {
const rendererRng = randomSupply.getIndexRng(1, vendor.renderers.length, window);
storage.rendererIndex = rendererRng(0);
}
windowHashes.set(window, storage);
}
return storage;
}
function getRandomVendorIndex(window){
return getWindowStorage(window).vendorIndex;
}
function getRandomRendererIndex(window){
return getWindowStorage(window).rendererIndex;
}
scope.getRandomVendor = function getRandomVendor(window){
return scope.vendors[getRandomVendorIndex(window)].vendor;
};
scope.getRandomRenderer = function getRandomRenderer(window){
const vendor = scope.vendors[getRandomVendorIndex(window)];
return vendor.renderers[getRandomRendererIndex(window)];
};
scope.pickOneFromTree = function pickOneFromTree(treeString, window){
function pickOne(string){
const options = [];
let cumulate = "";
let index = 0;
for (const l = string.length; index < l; index += 1){
const char = string.charAt(index);
if (char === "|"){
options.push(cumulate);
cumulate = "";
}
else if (char === "<"){
const subPick = pickOne(string.substring(index + 1));
cumulate += subPick.value;
index += 1 + subPick.endIndex;
}
else if (char === ">"){
break;
}
else {
cumulate += char;
}
}
options.push(cumulate);
const optionRng = randomSupply.getIndexRng(1, options.length, window);
return {value: options[optionRng(0)], endIndex: index};
}
return pickOne(treeString).value;
};
scope.vendors = [
{
vendor: "Chromium",
renderers: [
"Chromium",
]
},
{
vendor: "Intel Inc.",
renderers: [
"Intel GMA X3100 OpenGL Engine",
"Intel HD Graphics 3000 OpenGL Engine",
"Intel HD Graphics 4000 OpenGL Engine",
"Intel HD Graphics 5000 OpenGL Engine",
"Intel Iris OpenGL Engine",
"Intel Iris Pro OpenGL Engine",
]
},
{
vendor: "Intel Open Source Technology Center",
renderers: [
"Mesa DRI Intel(R) Haswell Mobile",
"Mesa DRI Intel(R) Ironlake Mobile",
"Mesa DRI Intel(R) Ivybridge Mobile x86/MMX/SSE2",
"Mesa DRI Intel(R) Ivybridge Mobile",
"Mesa DRI Intel(R) Sandybridge Desktop x86/MMX/SSE2",
"Mesa DRI Intel(R) Sandybridge Desktop",
"Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2",
"Mesa DRI Intel(R) Sandybridge Mobile",
]
},
{
vendor: "Google Inc.",
getRandomRenderer: function(window){
const words = "Series|Graphics|Chipset|Express|Family|nForce|Dual|NVIDIA|800|600|300|FireGL|Mobility|Radeon|series|FirePro|Optiplex|WDDM|200|400|700|70M|50M|Driver|200M".split("|");
const compressed = "ANGLE (<A<MD <760G|(ATI) $f M8900 ($b) $c Pro $1|$f <2270|W5000 ($b V) $1 Adapter>|M880G with ATI $c $d HD 42<00 |50>|$d< <HD<6<370D $1|410D $1>|77<00 $0|70>| <5<450|5<00 $0|70>|670|$k $0|$8 $0>|6<2<50< $1|M >|90 $1>|3<00 $e $1|10< $1 |M>|20< <$1 |$e $1>|M>|50|70<D|M>>|4<00M $0|10D|50A $1|$l |80G>|5<00< $0|M/5600/5700 $0>|10 $0|20G|30D $1|50A|70>|6<20G|30M|50A $1|70>|7<00 $0|30M>|$8 $0|900< $0|M $0>>|7<000 $e|290 $1|3<00 $0 $1|10< $1|M>|40< $1|G|M>>|4<00M $0|20G|50 $1|$l|80D>|5<00< $0|/7600 $0|G|M/7600M $0>|20G + 7670M $6 $1|40D|$m/7650M $1|60D|70< $1|M>|80D>|6<00<G + 6400M $6 $1|M $0>|10M|40G + <76<00M $6 $1|$l $6 $1>|8750M $6 $1>|$m|60<D|G + 7600M $6 $1>|$l>|$k $0|$8 $0|900 $0>|8<2<10|40|50>|3<30|50>|4<00|50G|70D>|5<10G|50G + <8570M $6 $1|HD 8600/8700M $6 $1>|70D>|6<10G + 8500M $6 $1|50G + 8<670M $6 $1|750M $6 $1>|70D>>>>|R<7 $i $0|9 $i $0>>|(TM) HD <6<380G|480G|520G |620G>|7450>>>|SUS <EAH<4350 $e|5<450 $0|670 $0|770 $0>|6<450 $0|670 $0|970 $0>>|HD7770 $0|R9 270 $0>|TI <$f <2450|V<3<$k ($b)|$8>|4800 ($b)>>|$c $d <9600/9700 $0|HD <2<$j XT|$9>|3<4<00 $0|30|50|70>|650>|4<2<00 $0|50 $1>|3<00< $0|/4500 $0>|30>|5<00< $0|/5100 $0>|30 $0|70>|650>|5<000 $0|145|4<00 $0 |30|5<0|v>|70 >|650>|6<370|550>>|X1<$a|$9>>|$d <2100|3<000 $1|100 $1>|HD<4670| <2<350|$j <P<ro |RO>|$0|XT >|$9 <P<ro |RO>|XT>>|3<$i $1|$a $1|4<00 $0|50 - Dell $g|70 - Dell $g>|6<00 $0|50>|$8 $0>|4<2<00|50 $1>|3<00< $0|/4500 $0>|50 $0>|550|6<00 Seri<es |si>|50|70>|770|8<00 $0|70 X2>>|5<4<00 $0|50>|570|6<00 $0|70>|$k $0|$8 $0>|6<230|350>>>|X<1<050|2<00 $0|50|70>>|$a/X550/X1050 $0|press <1<1<00|50 $0>|2<00 $0|50>>|$i $0>>>>>|Intel(R) <4 $0 Internal $2|829<15G/GV/910GL $3 $2 $4|45G $3 $2 $4>|946GZ $3 $2 $4|B43 $3 $2|G<33/G31 $3 $2 $4|4<1 $3 $2|5/G43 $3 $2>|965 $3 $2 $4|raphics Media Accelerator <3<150|$9 $0>|HD >>|HD $1 <3000|4<000|$j|$9>|$4>|Q<3<3 $3 $2 $4|5 $3 $2 $4>|45/Q43 $3 $2|965/Q963 $3 $2 $4>>|M<icrosoft Basic Render $n|obile Intel(R) <4<5 $3 $2 $4| $0 $3 $2 $4>|9<15GM/GMS,910GML $3 $2 $4|45< $3 $2 $4|GM $3 $2 $4>|65 $3 $2 $4>|- famiglia $3 $2 45|HD $1>>|$7 <GeForce <210 |31<0M |5M>|4<05M|10M>|6<05|1<0<0 $5 405|M>|50< LE|SE $5 430>>|$i TurboCache(TM)|500|$9>|7<0<00M / $5 610M|25 / $7 $5 630a |50 </ $7 $5 620i|PV / $7 $5 630a>>|1<00 </ $7 $5 630i|GS>|$m / $5 630M>|$a <G<S|T>|LE|SE/7200 GS>|900 GS>|8<$o G|$a GS |$j< GS|GS|M G<S|T>>|500 GT|$9< G<S|T< |S>>|GS|M G<S|T>>|$8 G<S|TS 512>>|9<100|$o GS|$a< GE|M GS >|$j< GT |M >|500< G<S|T>|M GS>|6<00< G<SO 512|T>|M G<S|T>>|$m GT>|700M GTS|$8 GT< |X/9800 GTX+>>|FX 5200|G<10<0|2M|5M>|210< |M>| 10<3M |5M >|o 7300|T< <120M|2<20|30M |40M >|3<20M|3<0M |5M>>|4<2<0M|5M>|30|40>|5<2<0M|5M>|30|45|55M>|6<10|2<0|5>|3<0M|5>|40< |M>|$m>|7<40M|55M>>|S <2<40|50>|350M|450 >|X <2<60|75|85|95>|4<60< SE|M>|80>|5<50 Ti|60< Ti |M>|70|80M>|6<50 Ti BOOST|60< Ti|M >|7<0|5M>|80|90>|7<60 (192-bit)|70|80>>>>>|ION|MCP67M|$5 750a SLI|NVS <3<00|100M >|4200M|5<100M|$o|400M >>|Quadro <1000M|2000M|$9|FX <1<500M|$k|$8>|2<500M|700M>|3700|5<70|80>|770M|880M>|K<3000M|$9>|NVS <1<10M|35M|40M|60M>|2<85|90>>>>|R<adeon <(TM) HD 64<$l|90M>|HD 6470M|X<1<$a/X1550 $0|550 <64-bit|$0>|650 S<E|eries >|950 $0>|$a/X550/X1050 $0|$8 GTO>>|DPDD Chained DD|oyal BNA $n|S880>|SiS Mirage 3 $1|VIA Chrome9 HC IGP $4 $h|WinFast GT 640($7)><| (Microsoft Corporation< <$h 1.1) |- $h< <1.<0)|1)|2)>|v1.<1)|2<0)|)>|3)>>|)>>|- $h v1.<1)|20)>>>< Direct3D<11 vs_<4_<0 ps_4_0|1 ps_4_1>|5_0 ps_5_0>|9<Ex|> vs_<0_0 ps_<2_0|3_0>|2_0 ps_2_0|3_0 ps_3_0>>|>)".replace(
/\$([0-9a-z]+)/gi,
function(m, index){
return words[parseInt(index, 36)];
}
);
return scope.pickOneFromTree(compressed, window);
}
},
{
vendor: "NVIDIA Corporation",
renderers: [
"GeForce 8600M GT/PCIe/SSE2",
"GeForce GT 430/PCIe/SSE2",
"GeForce GT 520/PCIe/SSE2",
"GeForce GTX 650 Ti/PCIe/SSE2",
"GeForce GTX 680/PCIe/SSE2",
"GeForce GTX 770/PCIe/SSE2",
"NVIDIA GeForce 320M OpenGL Engine",
"NVIDIA GeForce 8600M GT OpenGL Engine",
"NVIDIA GeForce 8800 GS OpenGL Engine",
"NVIDIA GeForce 8800 GT OpenGL Engine",
"NVIDIA GeForce 9400 OpenGL Engine",
"NVIDIA GeForce 9400M OpenGL Engine",
"NVIDIA GeForce 9600M GT OpenGL Engine",
"NVIDIA GeForce GT 130 OpenGL Engine",
"NVIDIA GeForce GT 330M OpenGL Engine",
"NVIDIA GeForce GT 640M OpenGL Engine",
"NVIDIA GeForce GT 650M OpenGL Engine",
"NVIDIA GeForce GT 750M OpenGL Engine",
"NVIDIA GeForce GTX 660M OpenGL Engine",
"NVIDIA GeForce GTX 675MX OpenGL Engine",
"NVIDIA GeForce GTX 680MX OpenGL Engine",
"Quadro 2000/PCIe/SSE2",
"Quadro 2000M/PCIe/SSE2",
"Quadro FX 1800/PCIe/SSE2",
"Quadro K600/PCIe/SSE2",
]
},
{
vendor: "VMware, Inc.",
renderers: [
"Gallium 0.4 on i915 (chipset: Pineview M)",
"Gallium 0.4 on llvmpipe (LLVM 3.2, 128 bits)",
]
},
{
vendor: "TransGaming Inc.",
renderers: [
"SwiftShader",
]
},
];
}());

View File

@ -2,7 +2,7 @@
{
"name": "CanvasBlocker",
"description": "__MSG_addon_description__",
"version": "1.1",
"version": "1.11",
"icons": {
"48": "icons/icon.svg",
"96": "icons/icon.svg"
@ -42,6 +42,7 @@
"lib/settings.js",
"lib/colorStatistics.js",
"lib/webglRandom.js",
"lib/webgl.js",
"lib/hash.js",
"lib/modifiedAPIFunctions.js",
@ -50,6 +51,8 @@
"lib/modifiedHistoryAPI.js",
"lib/modifiedWindowAPI.js",
"lib/modifiedDOMRectAPI.js",
"lib/modifiedSVGAPI.js",
"lib/modifiedTextMetricsAPI.js",
"lib/navigator.js",
"lib/modifiedNavigatorAPI.js",
"lib/modifiedScreenAPI.js",
@ -69,6 +72,7 @@
}],
"options_ui": {
"browser_style": false,
"open_in_tab": true,
"page": "options/options.html"
},
"browser_action": {
@ -87,7 +91,6 @@
"<all_urls>",
"storage",
"tabs",
"activeTab",
"webRequest",
"webRequestBlocking",
"contextualIdentities",
@ -95,11 +98,11 @@
"privacy"
],
"applications": {
"browser_specific_settings": {
"gecko": {
"id": "CanvasBlocker@kkapsner.de",
"update_url": "https://canvasblocker.kkapsner.de/versions/updates.json",
"strict_min_version": "68.0"
"strict_min_version": "100.0"
}
},
"default_locale": "en",

View File

@ -6,7 +6,7 @@ html, body {
#settings {
width: 100%;
box-sizing: border-box;
height: 95%;
height: 100%;
}
#settings.invalid {
background-color: var(--input-error-background-color);

View File

@ -274,9 +274,10 @@
const browserPresets = {
Edge: {
browserPreset: "Edge",
chromeVersion: "71.0.3578.98",
edgeVersion: "17.17134",
chromeVersion: "111.0.0.0",
edgeVersion: "111.0.1661.41",
firefoxVersion: undefined,
firefoxVersionRV: undefined,
operaVersion: undefined,
safariVersion: undefined,
@ -290,10 +291,11 @@
},
Opera: {
browserPreset: "Opera",
chromeVersion: "71.0.3578.98",
chromeVersion: "109.0.0.0",
edgeVersion: undefined,
firefoxVersion: undefined,
operaVersion: "58.0.3135.65",
firefoxVersionRV: undefined,
operaVersion: "95.0.0.0",
safariVersion: undefined,
appVersion: "5.0 ({platformDetails}) AppleWebKit/537.36 (KHTML, like Gecko) " +
@ -306,9 +308,10 @@
},
Chrome: {
browserPreset: "Chrome",
chromeVersion: "71.0.3578.98",
chromeVersion: "111.0.0.0",
edgeVersion: undefined,
firefoxVersion: undefined,
firefoxVersionRV: undefined,
operaVersion: undefined,
safariVersion: undefined,
@ -325,8 +328,9 @@
chromeVersion: undefined,
edgeVersion: undefined,
firefoxVersion: undefined,
firefoxVersionRV: undefined,
operaVersion: undefined,
safariVersion: "12.0.3",
safariVersion: "16.3",
appVersion: "5.0 ({platformDetails}) AppleWebKit/605.1.15 (KHTML, like Gecko) " +
"Version/{safariVersion} Safari/605.1.15",
@ -341,6 +345,7 @@
chromeVersion: undefined,
edgeVersion: undefined,
firefoxVersion: "{real Firefox version}",
firefoxVersionRV: "{real Firefox version - rv}",
operaVersion: undefined,
safariVersion: undefined,
@ -350,7 +355,7 @@
return firefoxOscpu[currentProperties.osPreset || ""] || "{original value}";
},
productSub: "20100101",
userAgent: "Mozilla/5.0 ({platformDetails}; rv:{firefoxVersion}) Gecko/20100101 Firefox/{firefoxVersion}",
userAgent: "Mozilla/5.0 ({platformDetails}; rv:{firefoxVersionRV}) Gecko/20100101 Firefox/{firefoxVersion}",
vendor: undefined,
}
};

View File

@ -1,5 +1,5 @@
body.standalone {
padding: 0.5em;
padding: 0.5em 0.5em 2.5em;
}
@media (max-width: 400px){
@ -37,7 +37,7 @@ header .bookmarkNotice .dontShowOptionsOnUpdate input {
vertical-align: sub;
}
.resistFingerprintingNotice {
.resistFingerprintingNotice, .settingsNotice {
margin: 0.5em 0;
padding: 0.5em;
border: 1px solid var(--input-error-background-color);
@ -68,7 +68,7 @@ header .bookmarkNotice .dontShowOptionsOnUpdate input {
.settings .section h2 {
border: 1px #c1c1c1 solid;
border-radius: 0.5em ;
border-radius: 0.5em;
padding: 0.2em 2em 0.2em 0.5em;
margin: 0.7em 1px 0.2em;
position: relative;

View File

@ -20,20 +20,23 @@
const mobile = require("../lib/mobile");
const callbacks = {
reloadExtension: function(){
browser.runtime.reload();
},
openNavigatorSettings: function(){
logging.verbose("open navigator settings");
window.open("navigator.html", "_blank");
browser.tabs.create({url: "navigator.html"});
},
showReleaseNotes: function(){
logging.verbose("open release notes");
window.open("../releaseNotes.txt", "_blank");
browser.tabs.create({url: extension.getURL("../releaseNotes.txt")});
},
clearPersistentRnd: function(){
logging.message("clear persistent rnd storage");
logging.notice("empty storage");
settings.persistentRndStorage = "";
logging.notice("send message to main script");
extension.message.send({"canvasBlocker-clear-domain-rnd": true});
extension.message.send({"canvasBlocker-clear-domain-rnd": "force"});
},
clearPersistentRndForContainer: async function(){
const identities = await browser.contextualIdentities.query({});
@ -50,15 +53,15 @@
},
inspectSettings: function(){
logging.verbose("open settings inspection");
window.open("export.html", "_blank");
browser.tabs.create({url: "export.html"});
},
openSettingSanitation: function(){
logging.verbose("open settings sanitation");
window.open("sanitize.html", "_blank");
browser.tabs.create({url: "sanitize.html"});
},
openSettingPresets: function(){
logging.verbose("open setting presets");
window.open("presets.html", "_blank");
browser.tabs.create({url: "presets.html"});
},
saveSettings: function(){
logging.verbose("save settings");
@ -89,13 +92,14 @@
},
inspectWhitelist: function(){
logging.verbose("open whitelist inspection");
window.open("whitelist.html", "_blank");
browser.tabs.create({url: "whitelist.html"});
},
loadSettings: async function(){
logging.verbose("load settings");
const text = await new Promise(function(resolve, reject){
const input = document.createElement("input");
input.type = "file";
input.accept = "application/json";
input.addEventListener("change", function(){
if (this.files.length){
const reader = new FileReader();
@ -230,28 +234,38 @@
groupTabs.classList = "groupTabs";
document.body.appendChild(groupTabs);
if (
browser.privacy &&
browser.privacy.websites &&
browser.privacy.websites.resistFingerprinting &&
browser.privacy.websites.resistFingerprinting.get
){
browser.privacy.websites.resistFingerprinting.get({}).then(function({value}){
if (value){
const rfpNotice = document.createElement("div");
rfpNotice.className = "resistFingerprintingNotice";
rfpNotice.appendChild(
extension.parseTranslation(
extension.getTranslation("resistFingerprintingNotice")
)
);
document.body.insertBefore(rfpNotice, groupTabs);
}
return undefined;
}).catch(function(error){
logging.warning("Unable to read resistFingerprinting:", error);
});
}
[
{
check: async function(){
if (
browser.privacy &&
browser.privacy.websites &&
browser.privacy.websites.resistFingerprinting &&
browser.privacy.websites.resistFingerprinting.get
){
return (await browser.privacy.websites.resistFingerprinting.get({})).value;
}
return false;
},
className: "resistFingerprintingNotice",
text: "resistFingerprintingNotice"
},
{
check: () => !window.AudioContext,
text: "settingsNotice.dom.webAudio.enabled"
},
].forEach(async function(settingsCheck){
if (await settingsCheck.check()){
const settingsNotice = document.createElement("div");
settingsNotice.className = settingsCheck.className || "settingsNotice";
settingsNotice.appendChild(
extension.parseTranslation(
extension.getTranslation(settingsCheck.text)
)
);
document.body.insertBefore(settingsNotice, groupTabs);
}
});
const groups = document.createElement("ul");
groups.className = "groups";
@ -573,7 +587,7 @@
const version = document.createElement("div");
version.className = "version";
fetch(browser.extension.getURL("manifest.json")).then(function(response){
fetch(extension.getURL("manifest.json")).then(function(response){
return response.json();
}).then(function(manifest){
version.textContent = "Version " + manifest.version;

View File

@ -51,10 +51,12 @@
const option = document.createElement("option");
if (typeof value === typeof setting.defaultValue){
option.value = value;
option.text = extension.getTranslation(setting.name + "_options." + value) || value;
if (setting.defaultValue === value){
option.selected = true;
option.selectedText = option.text;
option.notSelectedText = option.text + extension.getTranslation("labelForDefaultOption");
}
option.text = extension.getTranslation(setting.name + "_options." + value) || value;
}
else {
option.disabled = true;
@ -62,10 +64,29 @@
}
select.appendChild(option);
});
select.update = function(){
Array.from(select.options).forEach(function(option){
if (option.notSelectedText){
option.text = option.notSelectedText;
}
});
const selectedOption = select.options[select.selectedIndex];
if (selectedOption.selectedText){
selectedOption.text = selectedOption.selectedText;
}
};
return select;
}
const inputTypes = {
all: {
updateCallback: function(input, value, defaultValue){
if (input.update){
input.update();
}
input.classList[value === defaultValue? "remove": "add"]("changed");
}
},
number: {
input: function(value){
const input = document.createElement("input");
@ -73,8 +94,9 @@
input.value = value;
return input;
},
updateCallback: function(input, value){
updateCallback: function(input, value, defaultValue){
input.value = value;
inputTypes.all.updateCallback(input, value, defaultValue);
return input.value;
},
getValue: function(input){
@ -95,8 +117,9 @@
input.value = value;
return input;
},
updateCallback: function(input, value){
updateCallback: function(input, value, defaultValue){
input.value = value;
inputTypes.all.updateCallback(input, value, defaultValue);
return input.value;
},
getValue: function(input){
@ -111,8 +134,9 @@
input.style.display = "inline-block";
return input;
},
updateCallback: function(input, value){
updateCallback: function(input, value, defaultValue){
input.checked = value;
inputTypes.all.updateCallback(input, value, defaultValue);
return input.checked;
},
getValue: function(input){
@ -169,7 +193,7 @@
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
setting.defaultKeyValue
);
});
keyInput.addEventListener("change", function(){
@ -189,7 +213,7 @@
container && container.hasOwnProperty(key)?
container[key]:
setting.defaultKeyValue,
url
setting.defaultKeyValue
);
logging.message("setting", setting.name, "(", key, ") was not changed");
}
@ -225,11 +249,14 @@
urlCell.removeChild(input);
urlCell.textContent = entry.url;
});
input.addEventListener("click", function(event){
event.stopPropagation();
});
});
urlCell.textContent = entry.url;
row.appendChild(urlCell);
let input = createInput(setting, entry.url);
type.updateCallback(input, setting.get(entry.url));
type.updateCallback(input, setting.get(entry.url), setting.defaultValue);
if (!entry.hasOwnProperty(setting.name)){
input.classList.add("notSpecifiedForUrl");
}
@ -316,14 +343,17 @@
}
}
if (type){
setting.on(function(){type.updateCallback(input, setting.get(url));}, url);
setting.on(function(){
type.updateCallback(input, setting.get(url), setting.defaultValue);
}, url);
input.addEventListener("change", function(){
const value = type.getValue(input);
if (setting.set(value, url)){
type.updateCallback(input, value, setting.defaultValue);
logging.message("changed setting", setting.name, ":", value);
}
else {
type.updateCallback(input, setting.get(url));
type.updateCallback(input, setting.get(url), setting.defaultValue);
logging.message("setting", setting.name, "was not changed");
}
});

View File

@ -152,7 +152,7 @@
introduction.textContent = extension.getTranslation("presets_introduction");
head.appendChild(introduction);
const [settingsLoaded, presets] = await Promise.all([
const [, presets] = await Promise.all([
settings.loaded,
(await fetch("presets.json")).json()
]);

View File

@ -3,7 +3,12 @@
"maxFakeSize": 1000000,
"protectDOMRect": {
"mail.google.com": false,
"onedrive.live.com": false
"onedrive.live.com": false,
"^https://[^/]*ebay\\.([a-z]+|com\\.(au|hk|my|sg)|co\\.uk)(/|$)": false
},
"protectWindow": {
"paypal.com": false,
"dhl.de": false
}
},
"stealth": {

View File

@ -55,9 +55,12 @@
{
name: "disabledFeatures",
check: function(errorCallback){
const errorMessage = extension.getTranslation("sanitation_error.disabledFeatures");
function createErrorMessage(api){
return errorMessage.replace(/{api}/g, extension.getTranslation("section_" + api.section));
const allErrorMessage = extension.getTranslation("sanitation_error.disabledFeatures");
const someErrorMessage = extension.getTranslation("sanitation_error.disabledSomeFeatures");
function createErrorMessage(api, all = false){
return (all? allErrorMessage: someErrorMessage).replace(
/{api}/g,
extension.getTranslation("section_" + api.section));
}
const protectedFeatures = settings.getDefinition("protectedAPIFeatures");
const protectedFeaturesValue = protectedFeatures.get();
@ -80,35 +83,45 @@
{mainFlag: "protectAudio", section: "Audio-API"},
{mainFlag: "protectWindow", section: "Window-API"},
{mainFlag: "protectDOMRect", section: "DOMRect-API"},
{mainFlag: "protectSVG", section: "SVG-API"},
{mainFlag: "protectTextMetrics", section: "TextMetrics-API"},
{mainFlag: "protectNavigator", section: "Navigator-API"},
{mainFlag: "protectScreen", section: "Screen-API"},
].forEach(function(api){
if (settings.get(api.mainFlag) !== (api.mainFlagDisabledValue || false)){
if (getSectionKeys(api.section).every(function(key){
const sectionKeys = getSectionKeys(api.section);
if (sectionKeys.some(function(key){
return protectedFeaturesValue.hasOwnProperty(key) &&
!protectedFeaturesValue[key];
})){
const all = sectionKeys.every(function(key){
return protectedFeaturesValue.hasOwnProperty(key) &&
!protectedFeaturesValue[key];
});
const resolutions = [
{
label: extension.getTranslation("sanitation_resolution.enableFeatures"),
callback: function(){
const protectedFeaturesValue = protectedFeatures.get();
sectionKeys.forEach(function(key){
protectedFeaturesValue[key] = true;
});
protectedFeatures.set(protectedFeaturesValue);
}
},
];
if (all){
resolutions.push({
label: extension.getTranslation("sanitation_resolution.disableMainFlag"),
callback: function(){
settings.set(api.mainFlag, api.mainFlagDisabledValue || false);
}
});
}
errorCallback({
message: createErrorMessage(api),
severity: "high",
resolutions: [
{
label: extension.getTranslation("sanitation_resolution.enableFeatures"),
callback: function(){
const protectedFeaturesValue = protectedFeatures.get();
getSectionKeys(api.section).forEach(function(key){
protectedFeaturesValue[key] = true;
});
protectedFeatures.set(protectedFeaturesValue);
}
},
{
label: extension.getTranslation("sanitation_resolution.disableMainFlag"),
callback: function(){
settings.set(api.mainFlag, api.mainFlagDisabledValue || false);
}
},
]
message: createErrorMessage(api, all),
severity: all? "high": "medium",
resolutions
});
}
}

View File

@ -16,6 +16,14 @@
{
"name": "blockMode"
},
{
"name": "disruptSessionOnUpdate"
},
{
"name": "reloadExtension",
"actions": ["reloadExtension"],
"displayDependencies": [{"updatePending": [true]}]
},
]
},
{
@ -619,6 +627,44 @@
},
]
},
{
name: "SVG-API",
settings: [
{
"name": "protectSVG"
},
{
"name": "protectedAPIFeatures",
"replaceKeyPattern": / @ .+$/,
"displayedSection": "SVG-API",
"displayDependencies": [
{
"protectSVG": [true],
"displayAdvancedSettings": [true]
}
]
},
]
},
{
name: "TextMetrics-API",
settings: [
{
"name": "protectTextMetrics"
},
{
"name": "protectedAPIFeatures",
"replaceKeyPattern": / @ .+$/,
"displayedSection": "TextMetrics-API",
"displayDependencies": [
{
"protectTextMetrics": [true],
"displayAdvancedSettings": [true]
}
]
},
]
},
{
name: "Navigator-API",
settings: [

3
options/whitelist.css Normal file
View File

@ -0,0 +1,3 @@
.description {
margin: 1em 0;
}

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>CanvasBlocker whitelist inspection</title>
<link rel="stylesheet" type="text/css" media="screen" href="sanitize.css" />
<link rel="stylesheet" type="text/css" media="screen" href="whitelist.css" />
<link href="../icons/icon.svg" type="image/svg" rel="icon">
<link href="../icons/icon.svg" type="image/svg" rel="shortcut icon">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

Some files were not shown because too many files have changed in this diff Show More