Compare commits
335 Commits
0.5.15-RC1
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
5a1a318b91 | ||
|
e549267085 | ||
|
cee0f75293 | ||
|
91dd283b9a | ||
|
af5365b4eb | ||
|
1b76df7cbc | ||
|
474e929638 | ||
|
642d518110 | ||
|
4f366ed86c | ||
|
00e60074c3 | ||
|
3eedc7b7dc | ||
|
bebcec2139 | ||
|
5181a55071 | ||
|
a8e192fa9b | ||
|
0f3141ee12 | ||
|
e9ce4668fe | ||
|
acce01bfeb | ||
|
d159769997 | ||
|
56401048d1 | ||
|
54c625cd26 | ||
|
7bb3f00b45 | ||
|
b8c6115603 | ||
|
dacc578e12 | ||
|
825fa42141 | ||
|
40a8012ab0 | ||
|
ec95cbe11b | ||
|
36b54f3ab5 | ||
|
87790c9731 | ||
|
200f6b31f3 | ||
|
1d8bf95926 | ||
|
c6cf48c489 | ||
|
9a3745b366 | ||
|
a18e3ba37d | ||
|
645d0ac550 | ||
|
809c1270c5 | ||
|
a99a0615d0 | ||
|
bc13a5e2a2 | ||
|
8176ac83dc | ||
|
4a2079bf47 | ||
|
7229133c8d | ||
|
8bdedfcb3d | ||
|
ae40caed09 | ||
|
053ae6725e | ||
|
2a6c564ed8 | ||
|
8a84dd09f3 | ||
|
df039b0f3c | ||
|
fc5cce23ea | ||
|
e9f5f710e6 | ||
|
5df98e0cf5 | ||
|
6ea89b6318 | ||
|
02dfa8bd1b | ||
|
8dcfac442f | ||
|
27d8d61da6 | ||
|
fb1311a842 | ||
|
114b109340 | ||
|
4ce2f98b10 | ||
|
2c5b00a55d | ||
|
d6916b013e | ||
|
3b92824d0f | ||
|
d3558f0bd7 | ||
|
d55921ba92 | ||
|
1ca13299ec | ||
|
53ce86a21f | ||
|
269574ae17 | ||
|
3b08fdaf9b | ||
|
e0e6926a74 | ||
|
2ac1ec277d | ||
|
8e463a6164 | ||
|
2cefed00a7 | ||
|
7cd4b2e9fa | ||
|
8d3f489d11 | ||
|
34bc1730a1 | ||
|
f900c25900 | ||
|
6b172a0a4c | ||
|
46eb608f4e | ||
|
b46341de90 | ||
|
91b7dcbb11 | ||
|
582a962d8d | ||
|
d9c14d7eed | ||
|
4bd0c0c96c | ||
|
cfb09075eb | ||
|
4443d0a117 | ||
|
bb71b10c58 | ||
|
4d4cda678c | ||
|
6c6012edf4 | ||
|
05f8f936e9 | ||
|
1a199a5049 | ||
|
e5cba569ba | ||
|
fd09e3d5cf | ||
|
6aab7f68ea | ||
|
a92373f412 | ||
|
b4cb52df15 | ||
|
d100932236 | ||
|
bfa355b58d | ||
|
dc593daba8 | ||
|
029933964f | ||
|
ffd659c7bb | ||
|
f788cd4263 | ||
|
1bd87e6953 | ||
|
fb231a070b | ||
|
740b360485 | ||
|
3621fef625 | ||
|
3d603b84d4 | ||
|
d4fc7027eb | ||
|
4c364a9a72 | ||
|
863140c1ca | ||
|
640bd36b86 | ||
|
734e76180f | ||
|
78183f9efc | ||
|
f043acf41c | ||
|
892e4d2c34 | ||
|
d97864436d | ||
|
7f154c6cc6 | ||
|
6f5cfc1080 | ||
|
cca81c4006 | ||
|
2f6ca07bba | ||
|
8e4a881288 | ||
|
709093fa4d | ||
|
b9d5eb3d27 | ||
|
e8ee1f8e9c | ||
|
4ac02003de | ||
|
cf0243d487 | ||
|
34f9dfa4fd | ||
|
bce494e744 | ||
|
87646a152a | ||
|
de14490574 | ||
|
13203a905d | ||
|
277bef1227 | ||
|
015350c385 | ||
|
cdfe72fada | ||
|
57bf81ec3a | ||
|
43ea01c178 | ||
|
3722263a6f | ||
|
020a9c5b9a | ||
|
698fc02e66 | ||
|
7ae6e14d0d | ||
|
539ddf5e46 | ||
|
70a941f5aa | ||
|
51e76bafce | ||
|
8dddff85cc | ||
|
0d581403c1 | ||
|
0930928df3 | ||
|
a7d02efd09 | ||
|
aa3f9d878d | ||
|
211d6710f6 | ||
|
42b19a4ba5 | ||
|
16bef43945 | ||
|
b614b84b5f | ||
|
bde9d3c012 | ||
|
32af464c05 | ||
|
1e1f343f28 | ||
|
7cd4ecec44 | ||
|
4f5b9b5f78 | ||
|
be55cbf983 | ||
|
872e633025 | ||
|
ee87773ce2 | ||
|
28dd7f6819 | ||
|
a5558b4144 | ||
|
8e5986817e | ||
|
e48710eee9 | ||
|
1b04da40c2 | ||
|
afd426da58 | ||
|
0d160143c1 | ||
|
b94de2b641 | ||
|
945c2716c9 | ||
|
1f1d7052a1 | ||
|
e2c5dfc06e | ||
|
b4a744660b | ||
|
fcbc622cef | ||
|
f4d09e43ac | ||
|
ae526e4710 | ||
|
822218a00c | ||
|
4e6f76ab75 | ||
|
543365cd64 | ||
|
1125d6f1a8 | ||
|
7178b409c3 | ||
|
b7e1b50166 | ||
|
184b6bb47c | ||
|
586bc97d38 | ||
|
8f13588e61 | ||
|
8c852e96c9 | ||
|
23f2bf8b23 | ||
|
83394afc90 | ||
|
0f61318c27 | ||
|
716e6aa6a9 | ||
|
701eb979ed | ||
|
d5417cf807 | ||
|
c16068ca85 | ||
|
ef69e1dcb5 | ||
|
902d31b643 | ||
|
0a290b3521 | ||
|
e65ac94dda | ||
|
71c9baec0a | ||
|
ff98b9b9af | ||
|
3eea8fe7c4 | ||
|
3ab6366994 | ||
|
cd852a0c8b | ||
|
864c2454e1 | ||
|
8d7637e65b | ||
|
393020630c | ||
|
9779d14276 | ||
|
5ab00a5584 | ||
|
6a31bb3791 | ||
|
beb3a969f3 | ||
|
5964146e22 | ||
|
679265a82f | ||
|
d761411339 | ||
|
1b3709bce5 | ||
|
00e94f9ae4 | ||
|
c6bb9766f9 | ||
|
b9c9516b14 | ||
|
cb7a98d751 | ||
|
21a950565f | ||
|
d8b5ba0744 | ||
|
ce1925d95f | ||
|
2c1756ff07 | ||
|
c6e4027a7f | ||
|
5ac5c8cc66 | ||
|
46bf7e04f4 | ||
|
10b2ef8e70 | ||
|
ac2e074fdd | ||
|
d9adcb4c3d | ||
|
5b1c4bf6cc | ||
|
8cf58ebe3b | ||
|
2e91f85d8f | ||
|
2c141277e8 | ||
|
3e3dbf2698 | ||
|
0225f94890 | ||
|
253d3f68b1 | ||
|
da5a9f4509 | ||
|
a79c4ec8c5 | ||
|
7c2a4edde0 | ||
|
51b740632a | ||
|
9a7dd3c189 | ||
|
4fa91ef3ae | ||
|
64adb49b81 | ||
|
49f3c166a2 | ||
|
308d7c4005 | ||
|
87fa607d28 | ||
|
aae0fa2f8b | ||
|
d834b7a14b | ||
|
e2d18a143d | ||
|
8ee413a951 | ||
|
1fb7f7991b | ||
|
7cfc43194a | ||
|
e7cef53bac | ||
|
a9c89ff20c | ||
|
d9d2038f0c | ||
|
f2b55fe7a2 | ||
|
dd6fbc6c1f | ||
|
736aeb371d | ||
|
ec128796e3 | ||
|
692b4616e2 | ||
|
895f1a6f66 | ||
|
73e5f5737b | ||
|
d449e5f0c3 | ||
|
9614786406 | ||
|
0f1aa1cc32 | ||
|
13b061c395 | ||
|
00f69b73ab | ||
|
1cfdcdb120 | ||
|
73694ab129 | ||
|
59d78c8e68 | ||
|
84e40b5eb4 | ||
|
ada2845213 | ||
|
9e92e4baf2 | ||
|
f65d73f125 | ||
|
f03eb4a67a | ||
|
f674ee3328 | ||
|
f358951022 | ||
|
6fbb9339a1 | ||
|
64b60c834a | ||
|
350c7b65d4 | ||
|
3d881d3c7d | ||
|
8bfaf63a99 | ||
|
cc8ca147b0 | ||
|
01b63b356c | ||
|
b48ad91dfe | ||
|
282fcb12de | ||
|
6c22788096 | ||
|
9353f71455 | ||
|
1556ee45c2 | ||
|
f3f6df229f | ||
|
e2efb727b9 | ||
|
29e61ada25 | ||
|
d547917b43 | ||
|
363940014d | ||
|
16f88a5daa | ||
|
5de24ad430 | ||
|
38e56aff31 | ||
|
b0becc0af0 | ||
|
417b234a26 | ||
|
3334fa64c1 | ||
|
accdb3cec1 | ||
|
e50e9deca4 | ||
|
4337ccbf33 | ||
|
ade99bbb8a | ||
|
e1e313cb96 | ||
|
16fb042335 | ||
|
4020ba1ebd | ||
|
6312914ba3 | ||
|
9628497277 | ||
|
db3cb3be44 | ||
|
0e8938ba6e | ||
|
d09340e84f | ||
|
b361733c73 | ||
|
85c88ad3d8 | ||
|
ccabfc2a6f | ||
|
cc3127b0a4 | ||
|
4601dd25af | ||
|
8506757c62 | ||
|
e3182b562b | ||
|
abdb95b815 | ||
|
10413a89c3 | ||
|
372ee755f7 | ||
|
3dc39e11a5 | ||
|
627ee6d21e | ||
|
09286644d8 | ||
|
26e0d21b23 | ||
|
993e72d6c8 | ||
|
ce27426ad4 | ||
|
0d0e3e30ec | ||
|
717e1d3e3a | ||
|
a9ed208505 | ||
|
ddcaf5a2a9 | ||
|
6fb7622fec | ||
|
af1dfe755c | ||
|
0d331d91a6 | ||
|
15c537cd1f | ||
|
3ab687f45b | ||
|
3668f48247 | ||
|
14a4d1cdc2 | ||
|
32f9ea7447 | ||
|
8e414becf0 | ||
|
bf757a5431 |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"JAVASCRIPT": {
|
||||
"LOC": [70, 80, 100, 120],
|
||||
"LOC": [80, 90, 100, 120],
|
||||
"BLOCK_NESTING": [4, 5, 6, 7]
|
||||
}
|
||||
}
|
@ -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>
|
@ -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
|
||||
|
12
.documentation/default.css
Normal 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;
|
||||
}
|
9
.documentation/faq/funding.md
Normal 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.
|
5
.documentation/faq/howToSupport.md
Normal 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.
|
22
.documentation/faq/index.php
Normal 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>
|
9
.documentation/faq/missingSetting.md
Normal 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.
|
3
.documentation/faq/paypal.md
Normal 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.
|
9
.documentation/faq/permissions.md
Normal 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.
|
5
.documentation/faq/reCAPTCHA.md
Normal 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.
|
5
.documentation/faq/removeUrlSetting.md
Normal 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.
|
10
.documentation/faq/uniqueFingerprint.md
Normal 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.
|
@ -32,7 +32,7 @@
|
||||
"consistent-return": "error",
|
||||
"constructor-super": "warn",
|
||||
"eqeqeq": "error",
|
||||
"eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line"]}],
|
||||
"eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line", "globals"]}],
|
||||
"indent": ["error", "tab", {"SwitchCase": 1}],
|
||||
"max-depth": ["warn", 4],
|
||||
"max-len": ["warn", {"code": 120, "tabWidth": 4}],
|
||||
@ -50,8 +50,11 @@
|
||||
"no-unreachable": "warn",
|
||||
"no-unused-vars": "off",
|
||||
"no-use-before-define": ["error", {"functions": false}],
|
||||
"no-useless-rename": "warn",
|
||||
"no-useless-return": "warn",
|
||||
"no-var": "error",
|
||||
"quotes": ["error", "double"],
|
||||
"require-atomic-updates": "off",
|
||||
"semi": ["error", "always"],
|
||||
"space-in-parens": ["error", "never"],
|
||||
"strict": ["error", "function"],
|
||||
@ -67,7 +70,6 @@
|
||||
{
|
||||
"files": ["test/*"],
|
||||
"rules": {
|
||||
"no-var": "off",
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
|
18
.github/ISSUE_TEMPLATE.md
vendored
@ -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". -->
|
||||
~~~
|
125
.tools/build.js
Normal file
@ -0,0 +1,125 @@
|
||||
const child_process = require("child_process");
|
||||
const path = require("path");
|
||||
const yargs = require("yargs");
|
||||
const args = yargs
|
||||
.options("type", {
|
||||
alias: "t",
|
||||
describe: "Type of the build",
|
||||
choices: ["alpha", "rc", "release"],
|
||||
default: "alpha",
|
||||
})
|
||||
.help()
|
||||
.alias("help", "h")
|
||||
.argv;
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
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.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";
|
||||
throw "not implemented";
|
||||
}
|
||||
function getReleaseVersion(manifest){
|
||||
"use strict";
|
||||
return manifest.version.replace(/^([\d.]+).*$/, "$1");
|
||||
}
|
||||
|
||||
async function run(){
|
||||
"use strict";
|
||||
const manifestPath = path.join(__dirname, "../manifest.json");
|
||||
|
||||
const oldManifest = await fs.promises.readFile(manifestPath);
|
||||
const manifest = require(manifestPath);
|
||||
if (args.type === "alpha" || args.type === "rc"){
|
||||
manifest.name = "CanvasBlocker-Beta";
|
||||
["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";
|
||||
["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 = await getAlphaVersion(manifest);
|
||||
addAlphaVersionToUpdatesJSON(manifest.version);
|
||||
}
|
||||
else if (args.type === "rc"){
|
||||
manifest.version = getRCVersion(manifest);
|
||||
}
|
||||
else {
|
||||
manifest.version = getReleaseVersion(manifest);
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(manifestPath, JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
const childArgs = [
|
||||
"build",
|
||||
"--overwrite-dest",
|
||||
"--ignore-files",
|
||||
"test",
|
||||
"--ignore-files",
|
||||
"versions",
|
||||
"--ignore-files",
|
||||
"crowdin.yml",
|
||||
"--ignore-files",
|
||||
"package*"
|
||||
];
|
||||
const child = child_process.spawn("web-ext", childArgs, {stdio: "inherit"});
|
||||
child.on("close", function(){
|
||||
fs.promises.writeFile(manifestPath, oldManifest);
|
||||
});
|
||||
}
|
||||
run();
|
164
.tools/buildChromeVendors.js
Normal 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
@ -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)"
|
||||
]
|
@ -29,7 +29,6 @@ async function getMessagesInFile(path){
|
||||
return getMessagesInContent(content);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("file does not exist:", path);
|
||||
return [];
|
||||
}
|
||||
|
@ -83,12 +83,10 @@ async function translate(language){
|
||||
return data;
|
||||
}
|
||||
|
||||
translate(language).then(function(data){
|
||||
(async function(){
|
||||
"use strict";
|
||||
|
||||
return saveTranslation(language, data);
|
||||
}).catch(function(error){
|
||||
"use strict";
|
||||
const data = await translate(language);
|
||||
|
||||
console.error(error);
|
||||
});
|
||||
saveTranslation(language, data);
|
||||
}());
|
65
.vscode/settings.json
vendored
@ -1,55 +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",
|
||||
"ruleset",
|
||||
"spodermenpls",
|
||||
"unticking",
|
||||
"webgl",
|
||||
"whitelisted",
|
||||
"writeln",
|
||||
@ -63,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
@ -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",
|
||||
|
10
README.md
@ -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:
|
||||
* <canvas>: http://www.browserleaks.com/canvas
|
||||
* <canvas>: https://www.browserleaks.com/canvas
|
||||
* audio:
|
||||
* https://audiofingerprint.openwpm.com/ (very poorly written = slow)
|
||||
* https://webtransparency.cs.princeton.edu/webcensus/#audio-fp
|
||||
@ -44,6 +46,8 @@ The different block modes are:
|
||||
|
||||
-----
|
||||
|
||||
You can contribute to CanvasBlocker by translating it and/or improving the translations. For further instructions go to https://github.com/kkapsner/CanvasBlocker/issues/420.
|
||||
|
||||
Special thanks to:
|
||||
* spodermenpls for finding all the typos
|
||||
* Thorin-Oakenpants for the icon idea
|
||||
@ -58,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
@ -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": {
|
||||
@ -20,7 +20,15 @@
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_title_protectedAPIs": {
|
||||
"message": "\n \u00B7 {api}",
|
||||
"message": "\n · {api}",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_status_on": {
|
||||
"message": "CanvasBlocker an",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_status_off": {
|
||||
"message": "CanvasBlocker aus",
|
||||
"description": ""
|
||||
},
|
||||
"more": {
|
||||
@ -64,7 +72,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"options_title": {
|
||||
"message": "CanvasBlocker Einstellungen",
|
||||
"message": "CanvasBlocker-Einstellungen",
|
||||
"description": ""
|
||||
},
|
||||
"optionsIntroduction": {
|
||||
@ -83,10 +91,22 @@
|
||||
"message": "Bei Aktualisierung nicht wieder anzeigen.",
|
||||
"description": ""
|
||||
},
|
||||
"resistFingerprintingNotice": {
|
||||
"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": ""
|
||||
@ -96,7 +116,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"group_misc": {
|
||||
"message": "Vermischtes",
|
||||
"message": "Sonstiges",
|
||||
"description": ""
|
||||
},
|
||||
"section_asking": {
|
||||
@ -116,7 +136,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"section_misc": {
|
||||
"message": "Vermischtes",
|
||||
"message": "Sonstiges",
|
||||
"description": ""
|
||||
},
|
||||
"section_settings": {
|
||||
@ -143,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": ""
|
||||
@ -167,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": ""
|
||||
@ -263,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": ""
|
||||
@ -436,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": {
|
||||
@ -448,7 +520,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"rng_options.nonPersistent": {
|
||||
"message": "nicht persistent",
|
||||
"message": "nichtpersistent",
|
||||
"description": ""
|
||||
},
|
||||
"rng_options.white": {
|
||||
@ -572,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": {
|
||||
@ -580,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": {
|
||||
@ -588,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": {
|
||||
@ -596,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": {
|
||||
@ -667,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": ""
|
||||
@ -759,6 +839,10 @@
|
||||
"message": "Was soll erlaubt werden?",
|
||||
"description": ""
|
||||
},
|
||||
"selectWhitelistType": {
|
||||
"message": "Wie soll erlaubt werden?",
|
||||
"description": ""
|
||||
},
|
||||
"whitelistOnlyAPI": {
|
||||
"message": "Erlaube nur die {api}",
|
||||
"description": ""
|
||||
@ -1068,7 +1152,19 @@
|
||||
"description": ""
|
||||
},
|
||||
"protectWindow_askReCaptchaException": {
|
||||
"message": "Wenn die Window-API beschützt wird, funktioniert reCAPTCHA nicht mehr. Wollen Sie dafür eine Ausnahme hinzufügen?",
|
||||
"message": "Wenn die Window-API beschützt wird, funktioniert reCAPTCHA nicht mehr. Wollen Sie die window.name-API in eingebetteten Seiten erlauben, damit es wieder funktioniert?",
|
||||
"description": ""
|
||||
},
|
||||
"allowWindowNameInFrames_title": {
|
||||
"message": "Erlaube window.name in Frames",
|
||||
"description": ""
|
||||
},
|
||||
"allowWindowNameInFrames_description": {
|
||||
"message": "Die window.name-API ist im Kontext eingebetteter Seiten nicht besonders gefährlich und wird dort für legitime Anwendungen (z.B. reCAPTCHA) verwendet. Diese Einstellung erlaubt die Benutzung dort.",
|
||||
"description": ""
|
||||
},
|
||||
"allowWindowNameInFrames_urlSpecific": {
|
||||
"message": "Um dies nur für bestimmte Seiten zu erlauben, 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 setzen Sie das zugehörige Häkchen.",
|
||||
"description": ""
|
||||
},
|
||||
"protectDOMRect_title": {
|
||||
@ -1091,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": ""
|
||||
@ -1127,6 +1247,10 @@
|
||||
"message": "ACHTUNG: der tatsächlich verwendete Browser kann nicht komplett vorgetäuscht werden, da es eine Vielzahl von Möglichkeiten gibt, diesen zu detektieren. Z.B. kann er immer über Funktionalitätstests und die browser-spezifische Darstellung von HTML-Elementen bestimmt werden.",
|
||||
"description": ""
|
||||
},
|
||||
"navigatorSettings_contextualIdentities": {
|
||||
"message": "Es werden die Einstellungen der Tab-Umgebung {select} gezeigt.",
|
||||
"description": ""
|
||||
},
|
||||
"navigatorSettings_presetSection.os": {
|
||||
"message": "Betriebssystemvoreinstellungen",
|
||||
"description": ""
|
||||
@ -1164,7 +1288,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"screenSize_urlSpecific": {
|
||||
"message": "Um für bestimmte Seiten spezifische Werte zu verwenden, klicken Sie auf den schwarzen Pfeil um das Menü zu öffnen, fügen Sie die gewünsche Domain oder URL mit einem Klick auf \"+\" hinzu und geben sie den gewünschten Wert ein.",
|
||||
"message": "Um für bestimmte Seiten spezifische Werte zu verwenden, 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 geben sie den gewünschten Wert ein.",
|
||||
"description": ""
|
||||
},
|
||||
"fakeMinimalScreenSize_title": {
|
||||
@ -1335,6 +1459,10 @@
|
||||
"message": "Einstellungen",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_faq": {
|
||||
"message": "FAQ",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_test": {
|
||||
"message": "Testen",
|
||||
"description": ""
|
||||
@ -1395,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": ""
|
||||
@ -1428,7 +1560,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"sanitation_resolution.switchToNonPersistentRng": {
|
||||
"message": "wechsle zu \"nicht persistent\"",
|
||||
"message": "wechsle zu \"nichtpersistent\"",
|
||||
"description": ""
|
||||
},
|
||||
"sanitation_error.fakeEverythingInCanvas": {
|
||||
@ -1471,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": ""
|
||||
@ -1520,7 +1656,15 @@
|
||||
"description": ""
|
||||
},
|
||||
"preset_max_protection_description": {
|
||||
"message": "Maximiert den Schutz gegen die Fingerprint-Extraktion. Diese Einstellungen werden einige Seiten unbenutzbar machen, können den Browser etwas verlangsamen und es Seiten ermöglichen die Verwendung von CanvasBlocker zu detektieren.",
|
||||
"message": "Maximiert den Schutz gegen die Fingerprint-Extraktion. Diese Einstellungen werden einige Seiten unbenutzbar machen, können den Browser etwas verlangsamen und es Seiten ermöglichen die Verwendung von CanvasBlocker zu detektieren. Wenn Sie diese Voreinstellung angewendet haben, sollten Sie in Betracht ziehen auch die reCAPTCHA-Voreinstellung zu verwenden.",
|
||||
"description": ""
|
||||
},
|
||||
"preset_recaptcha_title": {
|
||||
"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, wodurch es wieder funktioniert.",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
@ -84,15 +92,28 @@
|
||||
"message": "CanvasBlocker was updated. If you want to be able to access this page in the future and have not bookmarked it yet, please bookmark it.",
|
||||
"description": ""
|
||||
},
|
||||
"dontShowOptionsOnUpdate":{
|
||||
"dontShowOptionsOnUpdate": {
|
||||
"message": "Don't show up again after update.",
|
||||
"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}.",
|
||||
"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": ""
|
||||
@ -130,31 +151,39 @@
|
||||
"message": "Settings",
|
||||
"description": ""
|
||||
},
|
||||
"section_canvas-api":{
|
||||
"section_canvas-api": {
|
||||
"message": "Canvas API",
|
||||
"description": ""
|
||||
},
|
||||
"section_audio-api":{
|
||||
"section_audio-api": {
|
||||
"message": "Audio API",
|
||||
"description": ""
|
||||
},
|
||||
"section_history-api":{
|
||||
"section_history-api": {
|
||||
"message": "History API",
|
||||
"description": ""
|
||||
},
|
||||
"section_window-api":{
|
||||
"section_window-api": {
|
||||
"message": "Window API",
|
||||
"description": ""
|
||||
},
|
||||
"section_DOMRect-api":{
|
||||
"section_DOMRect-api": {
|
||||
"message": "DOMRect API",
|
||||
"description": ""
|
||||
},
|
||||
"section_Navigator-api":{
|
||||
"section_SVG-api": {
|
||||
"message": "SVG API",
|
||||
"description": ""
|
||||
},
|
||||
"section_TextMetrics-api": {
|
||||
"message": "TextMetrics API",
|
||||
"description": ""
|
||||
},
|
||||
"section_Navigator-api": {
|
||||
"message": "Navigator API",
|
||||
"description": ""
|
||||
},
|
||||
"section_Screen-api":{
|
||||
"section_Screen-api": {
|
||||
"message": "Screen API",
|
||||
"description": ""
|
||||
},
|
||||
@ -177,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": ""
|
||||
@ -275,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": ""
|
||||
@ -304,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": {
|
||||
@ -319,32 +394,32 @@
|
||||
"message": "combined",
|
||||
"description": ""
|
||||
},
|
||||
"askDenyMode_title":{
|
||||
"askDenyMode_title": {
|
||||
"message": "Ask deny mode",
|
||||
"description": ""
|
||||
},
|
||||
"askDenyMode_description":{
|
||||
"askDenyMode_description": {
|
||||
"message": "Which mode shall be used when the permission is denied.",
|
||||
"description": ""
|
||||
},
|
||||
"askDenyMode_options.block":{
|
||||
"askDenyMode_options.block": {
|
||||
"message": "block",
|
||||
"description": ""
|
||||
},
|
||||
"askDenyMode_options.fake":{
|
||||
"askDenyMode_options.fake": {
|
||||
"message": "fake",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
"showCanvasWhileAsking_title":{
|
||||
"showCanvasWhileAsking_title": {
|
||||
"message": "Show canvas content",
|
||||
"description": ""
|
||||
},
|
||||
"showCanvasWhileAsking_description":{
|
||||
"showCanvasWhileAsking_description": {
|
||||
"message": "Shows the content of the canvas for which the permission is asked for, if possible.",
|
||||
"description": ""
|
||||
},
|
||||
"showCanvasWhileAsking_message":{
|
||||
"showCanvasWhileAsking_message": {
|
||||
"message": "The webpage wants to read the content of the following canvas:",
|
||||
"description": ""
|
||||
},
|
||||
@ -425,7 +500,7 @@
|
||||
},
|
||||
|
||||
"urlSettings_title": {
|
||||
"message": "Site specific values",
|
||||
"message": "Site-specific values",
|
||||
"description": ""
|
||||
},
|
||||
"urlSettings_description": {
|
||||
@ -457,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": {
|
||||
@ -469,7 +544,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"rng_options.nonPersistent": {
|
||||
"message": "non persistent",
|
||||
"message": "nonpersistent",
|
||||
"description": ""
|
||||
},
|
||||
"rng_options.white": {
|
||||
@ -602,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": {
|
||||
@ -610,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": {
|
||||
@ -618,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": {
|
||||
@ -626,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": ""
|
||||
},
|
||||
|
||||
@ -701,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": ""
|
||||
@ -795,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": ""
|
||||
@ -1111,7 +1198,20 @@
|
||||
"description": ""
|
||||
},
|
||||
"protectWindow_askReCaptchaException": {
|
||||
"message": "Protecting the window API breaks reCAPTCHA. Do you want to add an exception for it?",
|
||||
"message": "Protecting the window API breaks reCAPTCHA. Do you want to allow the window.name API in embedded pages which will make it work again?",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
"allowWindowNameInFrames_title": {
|
||||
"message": "Allow window.name in 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.",
|
||||
"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.",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
@ -1137,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": ""
|
||||
@ -1175,6 +1301,10 @@
|
||||
"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.",
|
||||
"description": ""
|
||||
},
|
||||
"navigatorSettings_contextualIdentities": {
|
||||
"message": "Settings for the container {select} are shown.",
|
||||
"description": ""
|
||||
},
|
||||
"navigatorSettings_presetSection.os": {
|
||||
"message": "Operating system presets",
|
||||
"description": ""
|
||||
@ -1394,6 +1524,10 @@
|
||||
"message": "Settings",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_faq": {
|
||||
"message": "FAQ",
|
||||
"description": ""
|
||||
},
|
||||
"browserAction_test": {
|
||||
"message": "Test",
|
||||
"description": ""
|
||||
@ -1455,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": ""
|
||||
@ -1488,7 +1626,7 @@
|
||||
"description": ""
|
||||
},
|
||||
"sanitation_resolution.switchToNonPersistentRng": {
|
||||
"message": "switch to \"non persistent\" rng",
|
||||
"message": "switch to \"nonpersistent\" rng",
|
||||
"description": ""
|
||||
},
|
||||
"sanitation_error.fakeEverythingInCanvas": {
|
||||
@ -1532,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": ""
|
||||
@ -1583,7 +1725,15 @@
|
||||
"description": ""
|
||||
},
|
||||
"preset_max_protection_description": {
|
||||
"message": "Maximizes the protection against fingerprint extraction. This settings will break some pages, might slow down the browser a little bit and might enable sites to detect that CanvasBlocker is used.",
|
||||
"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.",
|
||||
"description": ""
|
||||
},
|
||||
"preset_recaptcha_title": {
|
||||
"message": "reCAPTCHA exception",
|
||||
"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.",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
|
1670
_locales/hi/messages.json
Normal file
1670
_locales/ja/messages.json
Normal file
1670
_locales/ko/messages.json
Normal file
1670
_locales/lt/messages.json
Normal file
1670
_locales/nb/messages.json
Normal file
1670
_locales/pl/messages.json
Normal file
1670
_locales/pt/messages.json
Normal file
1670
_locales/pt_BR/messages.json
Normal file
1670
_locales/zh_TW/messages.json
Normal 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;
|
||||
}
|
@ -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>
|
||||
<script src="../lib/extension.js"></script>
|
||||
<div id="version" class="versionDisplay"></div>
|
||||
<script src="../lib/require.js"></script>
|
||||
<script src="../lib/logging.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>
|
@ -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);
|
||||
});
|
||||
}());
|
8
crowdin.yml
Normal file
@ -0,0 +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
|
110
icons/browserAction-CBoff.svg
Normal 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 |
105
icons/browserAction-CBon.svg
Normal 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
@ -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 |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
109
icons/browserAction-reload.svg
Normal 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 |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 7.9 KiB |
@ -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 |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.8 KiB |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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: {},
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, {
|
||||
|
285
lib/extension.js
@ -13,6 +13,7 @@
|
||||
}
|
||||
|
||||
const browserAvailable = typeof browser !== "undefined";
|
||||
const logging = require("./logging");
|
||||
|
||||
scope.inBackgroundScript = !!(
|
||||
browserAvailable &&
|
||||
@ -26,7 +27,56 @@
|
||||
return id;
|
||||
};
|
||||
|
||||
scope.extensionID = browserAvailable? browser.extension.getURL(""): "extensionID";
|
||||
scope.parseTranslation = function parseTranslation(message, parameters = {}){
|
||||
const container = document.createDocumentFragment();
|
||||
|
||||
message.split(/(\{[^}]+\})/).forEach(function(part){
|
||||
if (part.startsWith("{") && part.endsWith("}")){
|
||||
part = part.substring(1, part.length - 1);
|
||||
const args = part.split(":");
|
||||
switch (args[0]){
|
||||
case "image": {
|
||||
const image = document.createElement("img");
|
||||
image.className = "noticeImage";
|
||||
image.src = args.slice(1).join(":");
|
||||
container.appendChild(image);
|
||||
break;
|
||||
}
|
||||
case "link": {
|
||||
const link = document.createElement("a");
|
||||
link.target = "_blank";
|
||||
link.textContent = args[1];
|
||||
link.href = args.slice(2).join(":");
|
||||
container.appendChild(link);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (parameters[args[0]]){
|
||||
const parameter = parameters[args[0]];
|
||||
if ((typeof parameter) === "function"){
|
||||
container.appendChild(parameter(args.slice(1).join(":")));
|
||||
}
|
||||
else {
|
||||
container.appendChild(document.createTextNode(parameter));
|
||||
}
|
||||
}
|
||||
else {
|
||||
container.appendChild(document.createTextNode(part));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
container.appendChild(document.createTextNode(part));
|
||||
}
|
||||
});
|
||||
return container;
|
||||
};
|
||||
|
||||
scope.getURL = function getURL(str){
|
||||
return browser.runtime.getURL(str);
|
||||
};
|
||||
|
||||
scope.extensionID = browserAvailable? scope.getURL(""): "extensionID";
|
||||
|
||||
scope.inIncognitoContext = browserAvailable? browser.extension.inIncognitoContext: false;
|
||||
|
||||
@ -44,5 +94,238 @@
|
||||
};
|
||||
Object.seal(scope.message);
|
||||
|
||||
scope.getWrapped = function getWrapped(obj){
|
||||
return obj && (obj.wrappedJSObject || obj);
|
||||
};
|
||||
|
||||
scope.exportFunctionWithName = function exportFunctionWithName(func, context, name){
|
||||
const targetObject = scope.getWrapped(context).Object.create(null);
|
||||
const exportedTry = exportFunction(func, targetObject, {allowCrossOriginArguments: true, defineAs: name});
|
||||
if (exportedTry.name === name){
|
||||
return exportedTry;
|
||||
}
|
||||
else {
|
||||
if (func.name === name){
|
||||
logging.message(
|
||||
"FireFox bug: Need to change name in exportFunction from",
|
||||
exportedTry.name,
|
||||
"(originally correct) to",
|
||||
name
|
||||
);
|
||||
}
|
||||
else {
|
||||
logging.error("Wrong name specified for", name, new Error());
|
||||
}
|
||||
const wrappedContext = scope.getWrapped(context);
|
||||
const options = {
|
||||
allowCrossOriginArguments: true,
|
||||
defineAs: name
|
||||
};
|
||||
const oldDescriptor = Object.getOwnPropertyDescriptor(wrappedContext, name);
|
||||
if (oldDescriptor && !oldDescriptor.configurable){
|
||||
logging.error(
|
||||
"Unable to export function with the correct name", name,
|
||||
"instead we have to use", exportedTry.name
|
||||
);
|
||||
return exportedTry;
|
||||
}
|
||||
const exported = exportFunction(func, context, options);
|
||||
if (oldDescriptor){
|
||||
Object.defineProperty(wrappedContext, name, oldDescriptor);
|
||||
}
|
||||
else {
|
||||
delete wrappedContext[name];
|
||||
}
|
||||
return exported;
|
||||
}
|
||||
};
|
||||
|
||||
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){
|
||||
args = scope.getWrapped(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));
|
||||
if (!changedProperties){
|
||||
changedProperties = [];
|
||||
changedPropertiesByWindow.set(scope.getWrapped(window), changedProperties);
|
||||
}
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
const original = descriptor[type];
|
||||
descriptor[type] = changed;
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
changedProperties.push({group, object, name, type, original});
|
||||
};
|
||||
scope.revertProperties = function(window, group){
|
||||
window = scope.getWrapped(window);
|
||||
let changedProperties = changedPropertiesByWindow.get(window);
|
||||
if (!changedProperties){
|
||||
return;
|
||||
}
|
||||
if (group){
|
||||
const remainingProperties = changedProperties.filter(function(changedProperty){
|
||||
return changedProperty.group !== group;
|
||||
});
|
||||
changedPropertiesByWindow.set(window, remainingProperties);
|
||||
changedProperties = changedProperties.filter(function(changedProperty){
|
||||
return changedProperty.group === group;
|
||||
});
|
||||
}
|
||||
else {
|
||||
changedPropertiesByWindow.delete(window);
|
||||
}
|
||||
|
||||
for (let i = changedProperties.length - 1; i >= 0; i -= 1){
|
||||
const {object, name, type, original} = changedProperties[i];
|
||||
logging.verbose("reverting", name, "on", object);
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
descriptor[type] = original;
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
scope.waitSync = function waitSync(reason = "for no reason"){
|
||||
logging.message(`Starting synchronous request ${reason}.`);
|
||||
try {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "https://[::]", false);
|
||||
xhr.send();
|
||||
xhr = null;
|
||||
}
|
||||
catch (error){
|
||||
logging.verbose("Error in XHR:", error);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}());
|
56
lib/frame.js
@ -9,7 +9,6 @@
|
||||
const {ask} = require("./askForPermission");
|
||||
const {sha256String: hashing} = require("./hash");
|
||||
const {check: originalCheck, checkStack: originalCheckStack} = require("./check");
|
||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
||||
const extension = require("./extension");
|
||||
const iframeProtection = require("./iframeProtection");
|
||||
|
||||
@ -88,6 +87,8 @@
|
||||
logging.notice("my tab cookie store id is", data.cookieStoreId);
|
||||
const {persistent: persistentRnd} = require("./randomSupplies");
|
||||
persistentRnd.setCookieStoreId(data.cookieStoreId);
|
||||
const modifiedNavigatorAPI = require("./modifiedNavigatorAPI");
|
||||
modifiedNavigatorAPI.setCookieStoreId(data.cookieStoreId);
|
||||
}
|
||||
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
|
||||
if (data.hasOwnProperty(persistentRndName)){
|
||||
@ -126,14 +127,12 @@
|
||||
return settings.get(...args);
|
||||
}
|
||||
|
||||
|
||||
const interceptedWindows = new WeakMap();
|
||||
function interceptWindow(window){
|
||||
let wrappedTry;
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const href = window.location.href;
|
||||
wrappedTry = getWrapped(window);
|
||||
wrappedTry = extension.getWrapped(window);
|
||||
}
|
||||
catch (error){
|
||||
// we are unable to read the location due to SOP
|
||||
@ -146,9 +145,15 @@
|
||||
if (!enabled || interceptedWindows.get(wrappedWindow)){
|
||||
return false;
|
||||
}
|
||||
if (wrappedWindow.matchMedia(extensionSecret[0]) === extensionSecret[1]){
|
||||
interceptedWindows.set(wrappedWindow, true);
|
||||
return false;
|
||||
const canvasBlockerData = wrappedWindow.matchMedia(extensionSecret[0]);
|
||||
if (canvasBlockerData.secret === extensionSecret[1]){
|
||||
if (wrappedWindow.top === wrappedWindow){
|
||||
canvasBlockerData.undoIntercept(extension.extensionID);
|
||||
}
|
||||
else {
|
||||
interceptedWindows.set(wrappedWindow, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
logging.message("intercepting window", window);
|
||||
@ -170,17 +175,28 @@
|
||||
|
||||
const matchMediaDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow, "matchMedia");
|
||||
const originalMatchMedia = matchMediaDescriptor.value;
|
||||
matchMediaDescriptor.value = exportFunction(function matchMedia(query){
|
||||
if (query === extensionSecret[0]){
|
||||
return extensionSecret[1];
|
||||
}
|
||||
else {
|
||||
return arguments.length > 1?
|
||||
originalMatchMedia.apply(this, wrappedWindow.Array.from(arguments)):
|
||||
originalMatchMedia.call(this, query);
|
||||
}
|
||||
}, window);
|
||||
Object.defineProperty(wrappedWindow, "matchMedia", matchMediaDescriptor);
|
||||
extension.changeProperty(window, "matchMedia", {
|
||||
object: wrappedWindow,
|
||||
name: "matchMedia",
|
||||
type: "value",
|
||||
changed: extension.exportFunctionWithName(function matchMedia(query){
|
||||
if (query === extensionSecret[0]){
|
||||
return {
|
||||
secret: extensionSecret[1],
|
||||
undoIntercept: function(token){
|
||||
if (token === extension.extensionID){
|
||||
extension.revertProperties(window);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
return arguments.length > 1?
|
||||
originalMatchMedia.call(this, ...arguments):
|
||||
originalMatchMedia.call(this, query);
|
||||
}
|
||||
}, window, originalMatchMedia.name)
|
||||
});
|
||||
|
||||
interceptedWindows.set(wrappedWindow, true);
|
||||
return true;
|
||||
@ -189,6 +205,10 @@
|
||||
logging.message("register listener for messages from background script");
|
||||
extension.message.on(function(data){
|
||||
if (data["canvasBlocker-unload"]){
|
||||
extension.revertProperties(window);
|
||||
for (let frameIndex = 0; frameIndex < window.length; frameIndex += 1){
|
||||
extension.revertProperties(window[frameIndex]);
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
if (
|
||||
|
@ -13,6 +13,7 @@
|
||||
}
|
||||
|
||||
const settings = require("./settings");
|
||||
const extension = require("./extension");
|
||||
const lists = require("./lists");
|
||||
|
||||
function isWhitelisted(url){
|
||||
@ -23,23 +24,15 @@
|
||||
function changeProperty(object, name, type, changed){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
const original = descriptor[type];
|
||||
descriptor[type] = changed;
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
registerChangedProperty(object, name, descriptor, type, original);
|
||||
}
|
||||
const changedProperties = [];
|
||||
// eslint-disable-next-line max-params
|
||||
function registerChangedProperty(object, name, descriptor, type, original){
|
||||
changedProperties.push({object, name, descriptor, type, original});
|
||||
if ((typeof changed) === "function"){
|
||||
changed = extension.createProxyFunction(window, original, changed);
|
||||
}
|
||||
extension.changeProperty(window, "iframeProtection", {object, name, type, changed});
|
||||
}
|
||||
if (settings.isStillDefault){
|
||||
settings.onloaded(function(){
|
||||
if (isWhitelisted(window.location)){
|
||||
changedProperties.forEach(function({object, name, descriptor, type, original}){
|
||||
descriptor[type] = original;
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
});
|
||||
changedProperties.length = 0;
|
||||
extension.revertProperties(window, "iframeProtection");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -48,6 +41,9 @@
|
||||
return false;
|
||||
}
|
||||
}
|
||||
window.addEventListener("unload", function(){
|
||||
extension.revertProperties(window, "iframeProtection");
|
||||
});
|
||||
return changeProperty;
|
||||
}
|
||||
|
||||
@ -70,10 +66,9 @@
|
||||
return window;
|
||||
}
|
||||
};
|
||||
changeProperty(wrappedConstructor.prototype, "contentWindow", "get", exportFunction(
|
||||
Object.getOwnPropertyDescriptor(contentWindowTemp, "contentWindow").get,
|
||||
window
|
||||
));
|
||||
changeProperty(wrappedConstructor.prototype, "contentWindow", "get",
|
||||
Object.getOwnPropertyDescriptor(contentWindowTemp, "contentWindow").get
|
||||
);
|
||||
|
||||
const contentDocumentDescriptor = Object.getOwnPropertyDescriptor(
|
||||
constructor.prototype,
|
||||
@ -89,10 +84,9 @@
|
||||
return document;
|
||||
}
|
||||
};
|
||||
changeProperty(wrappedConstructor.prototype, "contentDocument", "get", exportFunction(
|
||||
Object.getOwnPropertyDescriptor(contentDocumentTemp, "contentDocument").get,
|
||||
window
|
||||
));
|
||||
changeProperty(wrappedConstructor.prototype, "contentDocument", "get",
|
||||
Object.getOwnPropertyDescriptor(contentDocumentTemp, "contentDocument").get
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -129,41 +123,42 @@
|
||||
protectionDefinition.methods.forEach(function(method){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, method);
|
||||
const original = descriptor.value;
|
||||
changeProperty(object, method, "value", exportFunction(eval(`(function ${method}(){
|
||||
const value = arguments.length?
|
||||
original.apply(this, window.Array.from(arguments)):
|
||||
original.call(this);
|
||||
allCallback();
|
||||
return value;
|
||||
})`), window));
|
||||
changeProperty(object, method, "value", class {
|
||||
[method](){
|
||||
const value = arguments.length?
|
||||
original.call(this, ...arguments):
|
||||
original.call(this);
|
||||
allCallback();
|
||||
return value;
|
||||
}
|
||||
}.prototype[method]);
|
||||
});
|
||||
protectionDefinition.getters.forEach(function(property){
|
||||
const temp = eval(`({
|
||||
get ${property}(){
|
||||
const ret = this.${property};
|
||||
const temp = {
|
||||
get [property](){
|
||||
const ret = this[property];
|
||||
allCallback();
|
||||
return ret;
|
||||
}
|
||||
})`);
|
||||
changeProperty(object, property, "get", exportFunction(
|
||||
Object.getOwnPropertyDescriptor(temp, property).get,
|
||||
window
|
||||
));
|
||||
};
|
||||
changeProperty(object, property, "get",
|
||||
Object.getOwnPropertyDescriptor(temp, property).get
|
||||
);
|
||||
});
|
||||
protectionDefinition.setters.forEach(function(property){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
||||
const setter = descriptor.set;
|
||||
const temp = eval(`({
|
||||
set ${property}(value){
|
||||
const temp = {
|
||||
set [property](value){
|
||||
const ret = setter.call(this, value);
|
||||
// const ret = this.${property} = value;
|
||||
allCallback();
|
||||
return ret;
|
||||
}
|
||||
})`);
|
||||
changeProperty(object, property, "set", exportFunction(
|
||||
Object.getOwnPropertyDescriptor(temp, property).set, window
|
||||
));
|
||||
};
|
||||
changeProperty(object, property, "set",
|
||||
Object.getOwnPropertyDescriptor(temp, property).set
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -204,8 +199,7 @@
|
||||
documentWriteDescriptorOnHTMLDocument?
|
||||
wrappedWindow.HTMLDocument.prototype:
|
||||
wrappedWindow.Document.prototype,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
"write", "value", exportFunction(function write(markup){
|
||||
"write", "value", function write(markup){
|
||||
for (let i = 0, l = arguments.length; i < l; i += 1){
|
||||
const str = "" + arguments[i];
|
||||
// weird problem with waterfox and google docs
|
||||
@ -223,7 +217,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
|
||||
const documentWritelnDescriptorOnHTMLDocument = Object.getOwnPropertyDescriptor(
|
||||
@ -239,26 +233,22 @@
|
||||
documentWritelnDescriptorOnHTMLDocument?
|
||||
wrappedWindow.HTMLDocument.prototype:
|
||||
wrappedWindow.Document.prototype,
|
||||
"writeln", "value", exportFunction(
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function writeln(markup){
|
||||
for (let i = 0, l = arguments.length; i < l; i += 1){
|
||||
const str = "" + arguments[i];
|
||||
const parts = str.split(/(?=<)/);
|
||||
const length = parts.length;
|
||||
const scripts = window.document.getElementsByTagName("script");
|
||||
for (let i = 0; i < length; i += 1){
|
||||
documentWrite.call(this, parts[i]);
|
||||
allCallback();
|
||||
if (scripts.length && scripts[scripts.length - 1].src){
|
||||
observe();
|
||||
}
|
||||
"writeln", "value", function writeln(markup){
|
||||
for (let i = 0, l = arguments.length; i < l; i += 1){
|
||||
const str = "" + arguments[i];
|
||||
const parts = str.split(/(?=<)/);
|
||||
const length = parts.length;
|
||||
const scripts = window.document.getElementsByTagName("script");
|
||||
for (let i = 0; i < length; i += 1){
|
||||
documentWrite.call(this, parts[i]);
|
||||
allCallback();
|
||||
if (scripts.length && scripts[scripts.length - 1].src){
|
||||
observe();
|
||||
}
|
||||
}
|
||||
documentWriteln.call(this, "");
|
||||
},
|
||||
window
|
||||
)
|
||||
}
|
||||
documentWriteln.call(this, "");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -274,9 +264,9 @@
|
||||
).get;
|
||||
changeProperty(
|
||||
wrappedWindow,
|
||||
"open", "value", exportFunction(function open(){
|
||||
"open", "value", function open(){
|
||||
const newWindow = arguments.length?
|
||||
windowOpen.apply(this, window.Array.from(arguments)):
|
||||
windowOpen.call(this, ...arguments):
|
||||
windowOpen.call(this);
|
||||
if (newWindow){
|
||||
// if we use windowOpen from the normal window we see some SOP errors
|
||||
@ -284,7 +274,7 @@
|
||||
singleCallback(getDocument.call(newWindow).defaultView);
|
||||
}
|
||||
return newWindow;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
281
lib/intercept.js
@ -14,7 +14,6 @@
|
||||
|
||||
const {changedFunctions, changedGetters, setRandomSupply} = require("./modifiedAPI");
|
||||
const randomSupplies = require("./randomSupplies");
|
||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
||||
const logging = require("./logging");
|
||||
const settings = require("./settings");
|
||||
const extension = require("./extension");
|
||||
@ -40,6 +39,9 @@
|
||||
settings.on("rng", function(){
|
||||
setRandomSupplyByType(settings.rng);
|
||||
});
|
||||
if (!settings.isStillDefault){
|
||||
setRandomSupplyByType(settings.rng);
|
||||
}
|
||||
|
||||
function getURL(windowToProcess){
|
||||
let href;
|
||||
@ -68,7 +70,7 @@
|
||||
[changedFunction.object]
|
||||
).map(function(name){
|
||||
if (name){
|
||||
const constructor = getWrapped(windowToProcess)[name];
|
||||
const constructor = extension.getWrapped(windowToProcess)[name];
|
||||
if (constructor){
|
||||
return constructor.prototype;
|
||||
}
|
||||
@ -77,7 +79,7 @@
|
||||
}).concat(
|
||||
changedFunction.objectGetters?
|
||||
changedFunction.objectGetters.map(function(objectGetter){
|
||||
return objectGetter(getWrapped(windowToProcess));
|
||||
return objectGetter(extension.getWrapped(windowToProcess));
|
||||
}):
|
||||
[]
|
||||
);
|
||||
@ -85,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});
|
||||
@ -96,7 +101,7 @@
|
||||
changedGetters.forEach(function(changedGetter){
|
||||
const name = changedGetter.name;
|
||||
changedGetter.objectGetters.forEach(function(changedGetter){
|
||||
const object = changedGetter(getWrapped(windowToProcess));
|
||||
const object = changedGetter(extension.getWrapped(windowToProcess));
|
||||
if (object){
|
||||
callback({name, object, objectGetter: changedGetter});
|
||||
}
|
||||
@ -144,40 +149,44 @@
|
||||
}
|
||||
|
||||
map.set(object, originalPropertyDescriptor);
|
||||
const temp = class {
|
||||
[`get ${name}`](){
|
||||
if (forceLoad){
|
||||
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
|
||||
undoPreIntercept();
|
||||
settings.forceLoad();
|
||||
doRealIntercept(windowToProcess, apis, state);
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
return descriptor.value || descriptor.get.call(this);
|
||||
}
|
||||
else {
|
||||
logging.notice("API blocked (%s)", name);
|
||||
const url = getURL(windowToProcess);
|
||||
if (!url){
|
||||
return undef;
|
||||
}
|
||||
const error = new Error();
|
||||
apis.notify({
|
||||
url,
|
||||
errorStack: error.stack,
|
||||
messageId: "preBlock",
|
||||
timestamp: new Date(),
|
||||
functionName: name,
|
||||
dataURL: false
|
||||
});
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
[`set ${name}`](newValue){}
|
||||
}.prototype;
|
||||
Object.defineProperty(
|
||||
object,
|
||||
name,
|
||||
{
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: exportFunction(function(){
|
||||
if (forceLoad){
|
||||
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
|
||||
undoPreIntercept();
|
||||
settings.forceLoad();
|
||||
doRealIntercept(windowToProcess, apis, state);
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
return descriptor.value || descriptor.get.call(this);
|
||||
}
|
||||
else {
|
||||
logging.notice("API blocked (%s)", name);
|
||||
const url = getURL(windowToProcess);
|
||||
if (!url){
|
||||
return undef;
|
||||
}
|
||||
const error = new Error();
|
||||
apis.notify({
|
||||
url,
|
||||
errorStack: error.stack,
|
||||
messageId: "preBlock",
|
||||
timestamp: new Date(),
|
||||
functionName: name,
|
||||
dataURL: false
|
||||
});
|
||||
return undef;
|
||||
}
|
||||
}, windowToProcess),
|
||||
set: exportFunction(function(){}, windowToProcess)
|
||||
get: extension.exportFunctionWithName(temp[`get ${name}`], windowToProcess, `get ${name}`),
|
||||
set: extension.exportFunctionWithName(temp[`set ${name}`], windowToProcess, `set ${name}`)
|
||||
}
|
||||
);
|
||||
});
|
||||
@ -231,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 {
|
||||
@ -314,42 +323,50 @@
|
||||
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){
|
||||
getAllFunctionObjects(windowToProcess, changedFunction).forEach(function(object){
|
||||
if (object){
|
||||
const original = object[name];
|
||||
const checker = generateChecker({
|
||||
name, changedFunction, siteStatus, original,
|
||||
window: windowToProcess, prefs, checkStack, ask, notify
|
||||
});
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
if (descriptor){
|
||||
if (descriptor.hasOwnProperty("value")){
|
||||
if (changedFunction.fakeGenerator){
|
||||
descriptor.value = exportFunction(
|
||||
changedFunction.fakeGenerator(checker, original, windowToProcess),
|
||||
windowToProcess
|
||||
);
|
||||
}
|
||||
else {
|
||||
descriptor.value = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
descriptor.get = exportFunction(function(){
|
||||
return exportFunction(
|
||||
changedFunction.fakeGenerator(checker),
|
||||
windowToProcess
|
||||
);
|
||||
}, windowToProcess);
|
||||
}
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
if (!functionStatus.active) return;
|
||||
|
||||
getAllFunctionObjects(windowToProcess, changedFunction).forEach(function(object){
|
||||
if (!object) return;
|
||||
|
||||
const original = object[name];
|
||||
const checker = generateChecker({
|
||||
name, changedFunction, siteStatus, original,
|
||||
window: windowToProcess, prefs, checkStack, ask, notify
|
||||
});
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
if (!descriptor) return;
|
||||
const type = descriptor.hasOwnProperty("value")? "value": "get";
|
||||
let changed;
|
||||
if (type ==="value"){
|
||||
if (changedFunction.fakeGenerator){
|
||||
const generated = changedFunction.fakeGenerator(checker, original, windowToProcess);
|
||||
if ((changedFunction.exportOptions || {}).allowCallbacks){
|
||||
changed = extension.exportFunctionWithName(generated, windowToProcess, original.name);
|
||||
}
|
||||
else {
|
||||
changed = extension.createProxyFunction(windowToProcess, original, generated);
|
||||
}
|
||||
}
|
||||
else {
|
||||
changed = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
changed = extension.createProxyFunction(windowToProcess, original, extension.exportFunctionWithName(
|
||||
changedFunction.fakeGenerator(checker),
|
||||
windowToProcess,
|
||||
original.name
|
||||
));
|
||||
}
|
||||
extension.changeProperty(windowToProcess, changedFunction.api, {
|
||||
object, name, type, changed
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function interceptGetters(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
|
||||
@ -357,70 +374,82 @@
|
||||
const name = changedGetter.name;
|
||||
const functionStatus = changedGetter.getStatus(undefined, siteStatus, prefs);
|
||||
logging.verbose("status for", changedGetter, ":", functionStatus);
|
||||
if (functionStatus.active){
|
||||
changedGetter.objectGetters.forEach(function(objectGetter){
|
||||
const object = objectGetter(getWrapped(windowToProcess));
|
||||
if (object){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
if (descriptor && descriptor.hasOwnProperty("get")){
|
||||
const original = descriptor.get;
|
||||
const checker = generateChecker({
|
||||
name, changedFunction: changedGetter, siteStatus, original,
|
||||
window: windowToProcess, prefs, checkStack, ask, notify
|
||||
});
|
||||
const getter = changedGetter.getterGenerator(checker, original, windowToProcess);
|
||||
descriptor.get = exportFunction(getter, windowToProcess);
|
||||
|
||||
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){
|
||||
const setter = changedGetter.setterGenerator(
|
||||
windowToProcess,
|
||||
descriptor.set,
|
||||
prefs
|
||||
);
|
||||
descriptor.set = exportFunction(setter, windowToProcess);
|
||||
if (!functionStatus.active) return;
|
||||
|
||||
changedGetter.objectGetters.forEach(function(objectGetter){
|
||||
const object = objectGetter(extension.getWrapped(windowToProcess));
|
||||
if (!object) return;
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||
if (!descriptor) return;
|
||||
|
||||
if (descriptor.hasOwnProperty("get")){
|
||||
const original = descriptor.get;
|
||||
const checker = generateChecker({
|
||||
name, changedFunction: changedGetter, siteStatus, original,
|
||||
window: windowToProcess, prefs, checkStack, ask, notify
|
||||
});
|
||||
const getter = changedGetter.getterGenerator(checker, original, windowToProcess);
|
||||
extension.changeProperty(windowToProcess, changedGetter.api,
|
||||
{
|
||||
object, name, type: "get",
|
||||
changed: extension.createProxyFunction(windowToProcess, original, getter)
|
||||
}
|
||||
);
|
||||
|
||||
if (descriptor.hasOwnProperty("set") && descriptor.set && changedGetter.setterGenerator){
|
||||
const original = descriptor.set;
|
||||
const setter = changedGetter.setterGenerator(
|
||||
windowToProcess,
|
||||
original,
|
||||
prefs
|
||||
);
|
||||
extension.changeProperty(windowToProcess, changedGetter.api,
|
||||
{
|
||||
object, name, type: "set",
|
||||
changed: extension.createProxyFunction(windowToProcess, original, setter)
|
||||
}
|
||||
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
}
|
||||
else if (
|
||||
changedGetter.valueGenerator &&
|
||||
descriptor && descriptor.hasOwnProperty("value")
|
||||
){
|
||||
const protectedAPIFeatures = prefs("protectedAPIFeatures");
|
||||
if (
|
||||
functionStatus.active &&
|
||||
(
|
||||
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedGetter.api) ||
|
||||
protectedAPIFeatures[name + " @ " + changedGetter.api]
|
||||
)
|
||||
){
|
||||
switch (functionStatus.mode){
|
||||
case "ask": case "block": case "fake":
|
||||
descriptor.value = changedGetter.valueGenerator({
|
||||
mode: functionStatus.mode,
|
||||
original: descriptor.value,
|
||||
notify: function notifyCallback(messageId){
|
||||
notify({
|
||||
url: getURL(windowToProcess),
|
||||
errorStack: (new Error()).stack,
|
||||
messageId,
|
||||
timestamp: new Date(),
|
||||
functionName: name,
|
||||
api: changedGetter.api
|
||||
});
|
||||
}
|
||||
});
|
||||
Object.defineProperty(object, name, descriptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
logging.error("Try to fake non getter property:", changedGetter);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else if (
|
||||
changedGetter.valueGenerator &&
|
||||
descriptor.hasOwnProperty("value")
|
||||
){
|
||||
const protectedAPIFeatures = prefs("protectedAPIFeatures");
|
||||
if (
|
||||
protectedAPIFeatures.hasOwnProperty(name + " @ " + changedGetter.api) &&
|
||||
!protectedAPIFeatures[name + " @ " + changedGetter.api]
|
||||
){
|
||||
return;
|
||||
}
|
||||
switch (functionStatus.mode){
|
||||
case "ask": case "block": case "fake":
|
||||
extension.changeProperty(windowToProcess, changedGetter.api, {
|
||||
object, name, type: "value",
|
||||
changed: changedGetter.valueGenerator({
|
||||
mode: functionStatus.mode,
|
||||
original: descriptor.value,
|
||||
notify: function notifyCallback(messageId){
|
||||
notify({
|
||||
url: getURL(windowToProcess),
|
||||
errorStack: (new Error()).stack,
|
||||
messageId,
|
||||
timestamp: new Date(),
|
||||
functionName: name,
|
||||
api: changedGetter.api
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
logging.error("Try to fake non getter property:", changedGetter);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
scope.intercept = function intercept({subject: windowToProcess}, apis){
|
||||
|
41
lib/lists.js
@ -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);
|
||||
@ -114,15 +128,28 @@
|
||||
}
|
||||
return lists[type];
|
||||
};
|
||||
scope.appendTo = function appendToList(type, entry){
|
||||
scope.appendTo = async function appendToList(type, entry){
|
||||
const oldValue = settings[type + "List"];
|
||||
return settings.set(type + "List", oldValue + (oldValue? ",": "") + entry).then(function(){
|
||||
return updateList(type);
|
||||
});
|
||||
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);
|
||||
|
@ -13,10 +13,11 @@
|
||||
}
|
||||
|
||||
let settings = false;
|
||||
scope.setSettings = function(realSettings){
|
||||
scope.setSettings = async function(realSettings){
|
||||
if (!settings){
|
||||
settings = realSettings;
|
||||
return settings.loaded.then(scope.clearQueue);
|
||||
await settings.loaded;
|
||||
return scope.clearQueue();
|
||||
}
|
||||
else {
|
||||
warning("logging: Settings can only be set once.");
|
||||
@ -77,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);}
|
||||
|
||||
|
95
lib/main.js
@ -10,11 +10,12 @@
|
||||
const persistentRndStorage = require("./persistentRndStorage");
|
||||
const notification = require("./notification");
|
||||
const mobile = require("./mobile");
|
||||
const extension = require("./extension");
|
||||
|
||||
const registerSettingsContentScript = (function(){
|
||||
let unregisterSettingsContentScript = function(){};
|
||||
let lastRegistering;
|
||||
return function registerSettingsContentScript(){
|
||||
return async function registerSettingsContentScript(){
|
||||
logging.message("Register content script for the settings.");
|
||||
logging.verbose("Unregister old content script, if present.");
|
||||
unregisterSettingsContentScript();
|
||||
@ -23,7 +24,7 @@
|
||||
data[def.name] = def.get();
|
||||
});
|
||||
lastRegistering = data;
|
||||
browser.contentScripts.register({
|
||||
const api = await browser.contentScripts.register({
|
||||
matches: ["<all_urls>"],
|
||||
matchAboutBlank: true,
|
||||
allFrames: true,
|
||||
@ -52,19 +53,16 @@
|
||||
}
|
||||
}(${JSON.stringify(data)}))`
|
||||
}]
|
||||
}).then(function(api){
|
||||
logging.verbose("Content script registered.");
|
||||
if (data !== lastRegistering){
|
||||
logging.verbose("Multiple content scripts registered at once. Remove unnecessary one.");
|
||||
api.unregister();
|
||||
}
|
||||
else {
|
||||
unregisterSettingsContentScript = api.unregister;
|
||||
}
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to register content script:", error);
|
||||
});
|
||||
|
||||
logging.verbose("Content script registered.");
|
||||
if (data !== lastRegistering){
|
||||
logging.verbose("Multiple content scripts registered at once. Remove unnecessary one.");
|
||||
api.unregister();
|
||||
}
|
||||
else {
|
||||
unregisterSettingsContentScript = api.unregister;
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
@ -79,7 +77,7 @@
|
||||
persistentRndStorage.init();
|
||||
|
||||
logging.message("register non port message listener");
|
||||
browser.runtime.onMessage.addListener(function(data){
|
||||
browser.runtime.onMessage.addListener(async function(data){
|
||||
logging.notice("got data without port", data);
|
||||
const keys = Object.keys(data);
|
||||
if (data["canvasBlocker-new-domain-rnd"]){
|
||||
@ -93,7 +91,7 @@
|
||||
}
|
||||
}
|
||||
if (data["canvasBlocker-clear-domain-rnd"]){
|
||||
persistentRndStorage.clear();
|
||||
persistentRndStorage.clear(data["canvasBlocker-clear-domain-rnd"] === "force");
|
||||
if (keys.length === 1){
|
||||
return;
|
||||
}
|
||||
@ -105,13 +103,9 @@
|
||||
}
|
||||
}
|
||||
logging.notice("pass the message to the tabs");
|
||||
browser.tabs.query({}).then(function(tabs){
|
||||
tabs.forEach(function(tab){
|
||||
browser.tabs.sendMessage(tab.id, data);
|
||||
});
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to get browser tabs:", error);
|
||||
const tabs = await browser.tabs.query({});
|
||||
tabs.forEach(function(tab){
|
||||
browser.tabs.sendMessage(tab.id, data);
|
||||
});
|
||||
});
|
||||
|
||||
@ -127,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
|
||||
});
|
||||
@ -168,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)
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -176,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":
|
||||
@ -190,12 +188,45 @@
|
||||
}
|
||||
|
||||
// mobile default settings
|
||||
mobile.ifMobile(function(){
|
||||
return browser.storage.local.get().then(mobile.applyMobileDefaults).catch(function(error){
|
||||
logging.error("Unable to set mobile default values:", error);
|
||||
});
|
||||
mobile.ifMobile(async function(){
|
||||
const settings = await browser.storage.local.get();
|
||||
mobile.applyMobileDefaults(settings);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
if (browser.runtime.onSuspend){
|
||||
browser.runtime.onSuspend.addListener(async function(){
|
||||
logging.message("Suspending CanvasBlocker");
|
||||
(await browser.tabs.query({})).forEach(function(tab){
|
||||
browser.tabs.sendMessage(tab.id, {
|
||||
"canvasBlocker-unload": true
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
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");
|
||||
}());
|
||||
|
@ -15,31 +15,33 @@
|
||||
const settings = require("./settings");
|
||||
const settingDefinitions = require("./settingDefinitions");
|
||||
|
||||
scope.isMobile = function isMobile(){
|
||||
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 Promise.resolve(
|
||||
!browser.pageAction ||
|
||||
return !browser.pageAction ||
|
||||
!browser.pageAction.show ||
|
||||
!browser.pageAction.openPopup
|
||||
);
|
||||
;
|
||||
};
|
||||
|
||||
scope.ifMobile = function ifMobile(ifCallback, elseCallback){
|
||||
return scope.isMobile().then(function(isMobile){
|
||||
if (isMobile){
|
||||
return ifCallback();
|
||||
}
|
||||
else if (elseCallback){
|
||||
return elseCallback();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
scope.ifMobile = async function ifMobile(ifCallback, elseCallback){
|
||||
const isMobile = await scope.isMobile();
|
||||
if (isMobile){
|
||||
return ifCallback();
|
||||
}
|
||||
else if (elseCallback){
|
||||
return elseCallback();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
scope.applyMobileDefaults = function applyMobileDefaults(storage = false){
|
||||
return Promise.all(settingDefinitions.filter(function(definition){
|
||||
scope.applyMobileDefaults = async function applyMobileDefaults(storage = false){
|
||||
await Promise.all(settingDefinitions.filter(function(definition){
|
||||
return definition.hasOwnProperty("mobileDefaultValue") && (
|
||||
!storage ||
|
||||
!storage.hasOwnProperty(definition.name)
|
||||
|
@ -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"));
|
||||
}());
|
@ -12,16 +12,12 @@
|
||||
scope = require.register("./modifiedAPIFunctions", {});
|
||||
}
|
||||
|
||||
scope.getWrapped = function getWrapped(obj){
|
||||
return obj && (obj.wrappedJSObject || obj);
|
||||
};
|
||||
|
||||
scope.checkerWrapper = function checkerWrapper(checker, object, args, callback){
|
||||
const check = checker.call(object);
|
||||
if (check.allow){
|
||||
if (check.allow === true){
|
||||
return args.length?
|
||||
check.original.apply(object, check.window.Array.from(args)):
|
||||
check.original.call(object, ...args):
|
||||
check.original.call(object);
|
||||
}
|
||||
return callback.call(object, args, check);
|
||||
@ -30,6 +26,14 @@
|
||||
return undefined;
|
||||
};
|
||||
|
||||
scope.getStatusByFlag = function getStatusByFlag(flag){
|
||||
return function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs(flag, status.url);
|
||||
return status;
|
||||
};
|
||||
};
|
||||
|
||||
scope.setFunctionProperties = function setFunctionProperties(functions, data){
|
||||
Object.keys(functions).forEach(function(key){
|
||||
const func = functions[key];
|
||||
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
|
||||
const {sha256String: hashing} = require("./hash");
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const {checkerWrapper, setFunctionProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||
|
||||
let randomSupply = null;
|
||||
|
||||
@ -156,26 +156,23 @@
|
||||
randomSupply = supply;
|
||||
};
|
||||
|
||||
function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs("protectAudio", status.url);
|
||||
return status;
|
||||
}
|
||||
|
||||
const getChannelDataAlreadyFakedArrays = new WeakMap();
|
||||
function fakeArrayCheckerCallback(array, fakeFunction, args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.call(this, ...args);
|
||||
fakeFunction(array, window, prefs);
|
||||
return ret;
|
||||
}
|
||||
// changed functions and their fakes
|
||||
scope.changedFunctions = {
|
||||
getFloatFrequencyData: {
|
||||
object: ["AnalyserNode"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getFloatFrequencyData(array){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
fakeFloat32Array(array, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments,
|
||||
fakeArrayCheckerCallback.bind(this, array, fakeFloat32Array)
|
||||
);
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -183,13 +180,9 @@
|
||||
object: ["AnalyserNode"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getByteFrequencyData(array){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
fakeUint8Array(array, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments,
|
||||
fakeArrayCheckerCallback.bind(this, array, fakeUint8Array)
|
||||
);
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -197,13 +190,9 @@
|
||||
object: ["AnalyserNode"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getFloatTimeDomainData(array){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
fakeFloat32Array(array, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments,
|
||||
fakeArrayCheckerCallback.bind(this, array, fakeFloat32Array)
|
||||
);
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -211,24 +200,19 @@
|
||||
object: ["AnalyserNode"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getByteTimeDomainData(array){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
fakeUint8Array(array, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments,
|
||||
fakeArrayCheckerCallback.bind(this, array, fakeUint8Array)
|
||||
);
|
||||
};
|
||||
}
|
||||
},
|
||||
getChannelData: {
|
||||
object: ["AudioBuffer"],
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function getChannelData(channel){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
const ret = original.call(this, ...args);
|
||||
if (!getChannelDataAlreadyFakedArrays.get(ret)){
|
||||
notify("fakedAudioReadout");
|
||||
fakeFloat32Array(ret, window, prefs);
|
||||
@ -242,7 +226,6 @@
|
||||
copyFromChannel: {
|
||||
object: ["AudioBuffer"],
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function copyFromChannel(destination, channelNumber, startInChannel){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
@ -252,7 +235,7 @@
|
||||
fakeFloat32Array(channelData, window, prefs);
|
||||
getChannelDataAlreadyFakedArrays.set(channelData, true);
|
||||
}
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
const ret = original.call(this, ...args);
|
||||
return ret;
|
||||
});
|
||||
};
|
||||
@ -261,12 +244,11 @@
|
||||
getFrequencyResponse: {
|
||||
object: ["BiquadFilterNode", "IIRFilterNode"],
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function getFrequencyResponse(frequencyArray, magResponseOutput, phaseResponseOutput){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
notify("fakedAudioReadout");
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
const ret = original.call(this, ...args);
|
||||
fakeFloat32Array(magResponseOutput, window, prefs);
|
||||
fakeFloat32Array(phaseResponseOutput, window, prefs);
|
||||
return ret;
|
||||
@ -275,9 +257,10 @@
|
||||
}
|
||||
},
|
||||
};
|
||||
Object.keys(scope.changedFunctions).forEach(function(key){
|
||||
scope.changedFunctions[key].type = "readout";
|
||||
scope.changedFunctions[key].getStatus = getStatus;
|
||||
scope.changedFunctions[key].api = "audio";
|
||||
|
||||
setFunctionProperties(scope.changedFunctions, {
|
||||
type: "readout",
|
||||
getStatus: getStatusByFlag("protectAudio"),
|
||||
api: "audio"
|
||||
});
|
||||
}());
|
@ -7,8 +7,9 @@
|
||||
const scope = ((typeof exports) !== "undefined")? exports: require.register("./modifiedCanvasAPI");
|
||||
const colorStatistics = require("./colorStatistics");
|
||||
const logging = require("./logging");
|
||||
const {copyCanvasToWebgl} = require("./webgl");
|
||||
const {getWrapped, checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const extension = require("./extension");
|
||||
const webgl = require("./webgl");
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
|
||||
let randomSupply = null;
|
||||
|
||||
@ -23,8 +24,8 @@
|
||||
let imageData;
|
||||
let source;
|
||||
if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){
|
||||
imageData = new (getWrapped(window).ImageData)(0, 0);
|
||||
source = new (getWrapped(window).ImageData)(0, 0);
|
||||
imageData = new (extension.getWrapped(window).ImageData)(0, 0);
|
||||
source = new (extension.getWrapped(window).ImageData)(0, 0);
|
||||
}
|
||||
else if (context instanceof window.CanvasRenderingContext2D){
|
||||
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(
|
||||
@ -35,7 +36,7 @@
|
||||
source = imageData.data;
|
||||
}
|
||||
else {
|
||||
imageData = new (getWrapped(window).ImageData)(context.canvas.width, context.canvas.height);
|
||||
imageData = new (extension.getWrapped(window).ImageData)(context.canvas.width, context.canvas.height);
|
||||
source = new Uint8Array(imageData.data.length);
|
||||
(
|
||||
context instanceof window.WebGLRenderingContext?
|
||||
@ -181,99 +182,134 @@
|
||||
|
||||
scope.setRandomSupply = function(supply){
|
||||
randomSupply = supply;
|
||||
webgl.setRandomSupply(supply);
|
||||
};
|
||||
|
||||
|
||||
function getNumber(originalValue, max, index, window){
|
||||
const bitLength = Math.floor(Math.log2(max) + 1);
|
||||
const rng = randomSupply.getBitRng(bitLength, window);
|
||||
let value = 0;
|
||||
for (let i = 0; i < bitLength; i += 1){
|
||||
value <<= 1;
|
||||
value ^= rng(originalValue, index + i);
|
||||
const canvasContextType = new WeakMap();
|
||||
function createGetStatus(protectedPart){
|
||||
if (protectedPart === "readout+"){
|
||||
return function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
if (!status.active && protectedPartChecker("input")){
|
||||
const contextType = canvasContextType.get(obj);
|
||||
status.active = contextType !== "2d";
|
||||
}
|
||||
return status;
|
||||
};
|
||||
}
|
||||
return value;
|
||||
return function getStatus(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker(protectedPart);
|
||||
return status;
|
||||
};
|
||||
}
|
||||
|
||||
const parameterFakeTypes = {
|
||||
decimal: function(originalValue, definition, window){
|
||||
const int = Math.floor(originalValue);
|
||||
if (int !== originalValue){
|
||||
const decimal = originalValue - int;
|
||||
const rng = randomSupply.getRng(1, window);
|
||||
const newDecimal = decimal * (rng(definition.pname) / 0xFFFFFFFF);
|
||||
return int + newDecimal;
|
||||
function useFakeCanvasCallback(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
||||
const fakeCanvas = getFakeCanvas(window, this, prefs);
|
||||
if (fakeCanvas !== this){
|
||||
notify("fakedReadout");
|
||||
}
|
||||
else {
|
||||
return originalValue;
|
||||
}
|
||||
},
|
||||
shift: function(originalValue, definition, window){
|
||||
const value = getNumber(originalValue, definition.max, definition.pname, window);
|
||||
return originalValue >>> value;
|
||||
},
|
||||
"-": function(originalValue, definition, window){
|
||||
const value = getNumber(originalValue, definition.max, definition.pname, window) *
|
||||
(definition.factor || 1);
|
||||
if (value > originalValue){
|
||||
return 0;
|
||||
}
|
||||
return originalValue - value;
|
||||
return original.call(fakeCanvas, ...args);
|
||||
}
|
||||
};
|
||||
const parameterChangeDefinition = {
|
||||
2928: {name: "DEPTH_RANGE", type: "decimal", isArray: true},
|
||||
3379: {name: "MAX_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
3386: {name: "MAX_VIEWPORT_DIMS", type: "shift", max: 1, isArray: true},
|
||||
32883: {name: "MAX_3D_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
33000: {name: "MAX_ELEMENTS_VERTICES", type: "-", max: 3, factor: 50},
|
||||
33001: {name: "MAX_ELEMENTS_INDICES", type: "-", max: 3, factor: 50},
|
||||
33901: {name: "ALIASED_POINT_SIZE_RANGE", type: "decimal", isArray: true},
|
||||
33902: {name: "ALIASED_LINE_WIDTH_RANGE", type: "decimal", isArray: true},
|
||||
34024: {name: "MAX_RENDERBUFFER_SIZE", type: "shift", max: 1},
|
||||
34045: {name: "MAX_TEXTURE_LOD_BIAS", type: "-", max: 1, factor: 1},
|
||||
34076: {name: "MAX_CUBE_MAP_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
34921: {name: "MAX_VERTEX_ATTRIBS", type: "shift", max: 1},
|
||||
34930: {name: "MAX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
||||
35071: {name: "MAX_ARRAY_TEXTURE_LAYERS", type: "shift", max: 1},
|
||||
35371: {name: "MAX_VERTEX_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
||||
35373: {name: "MAX_FRAGMENT_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
||||
35374: {name: "MAX_COMBINED_UNIFORM_BLOCKS", type: "-", max: 3, factor: 1},
|
||||
35375: {name: "MAX_UNIFORM_BUFFER_BINDINGS", type: "-", max: 3, factor: 1},
|
||||
35376: {name: "MAX_UNIFORM_BLOCK_SIZE", type: "shift", max: 1},
|
||||
35377: {name: "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
||||
35379: {name: "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
||||
35657: {name: "MAX_FRAGMENT_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
||||
35658: {name: "MAX_VERTEX_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
||||
35659: {name: "MAX_VARYING_COMPONENTS", type: "shift", max: 1},
|
||||
35660: {name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
||||
35661: {name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS", type: "-", max: 1, factor: 2},
|
||||
35968: {name: "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", type: "shift", max: 1},
|
||||
35978: {name: "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", type: "shift", max: 1},
|
||||
36203: {name: "MAX_ELEMENT_INDEX", type: "-", max: 15, factor: 1},
|
||||
36347: {name: "MAX_VERTEX_UNIFORM_VECTORS", type: "shift", max: 1},
|
||||
36348: {name: "MAX_VARYING_VECTORS", type: "shift", max: 1},
|
||||
36349: {name: "MAX_FRAGMENT_UNIFORM_VECTORS", type: "shift", max: 1},
|
||||
37154: {name: "MAX_VERTEX_OUTPUT_COMPONENTS", type: "shift", max: 1},
|
||||
37157: {name: "MAX_FRAGMENT_INPUT_COMPONENTS", type: "shift", max: 1},
|
||||
7936: {name: "VENDOR", fake: function(originalValue, window, prefs){
|
||||
const settingValue = prefs("webGLVendor") || originalValue;
|
||||
return {value: settingValue, faked: settingValue === originalValue};
|
||||
}},
|
||||
7937: {name: "RENDERER", fake: function(originalValue, window, prefs){
|
||||
const settingValue = prefs("webGLRenderer") || originalValue;
|
||||
return {value: settingValue, faked: settingValue === originalValue};
|
||||
}},
|
||||
37445: {name: "UNMASKED_VENDOR_WEBGL", fake: function(originalValue, window, prefs){
|
||||
const settingValue = prefs("webGLUnmaskedVendor") || originalValue;
|
||||
return {value: settingValue, faked: settingValue === originalValue};
|
||||
}},
|
||||
37446: {name: "UNMASKED_RENDERER_WEBGL", fake: function(originalValue, window, prefs){
|
||||
const settingValue = prefs("webGLUnmaskedRenderer") || originalValue;
|
||||
return {value: settingValue, faked: settingValue === originalValue};
|
||||
}}
|
||||
};
|
||||
const canvasContextType = new WeakMap();
|
||||
else {
|
||||
return original.call(this, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
function mixOnInputCallback(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
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
|
||||
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.call(this, x, y, width, height);
|
||||
this.putImageData(randomMixImageData(window, oldImageData, newImageData), x, y);
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return original.call(this, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
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: {
|
||||
@ -301,123 +337,57 @@
|
||||
},
|
||||
object: "HTMLCanvasElement",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function(context, contextAttributes){
|
||||
return function getContext(context, contextAttributes){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {window, original} = check;
|
||||
const {original} = check;
|
||||
canvasContextType.set(this, context);
|
||||
return original.apply(this, window.Array.from(args));
|
||||
return original.call(this, ...args);
|
||||
});
|
||||
};
|
||||
}
|
||||
},
|
||||
toDataURL: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
if (!status.active && protectedPartChecker("input")){
|
||||
const contextType = canvasContextType.get(obj);
|
||||
status.active = contextType !== "2d";
|
||||
}
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout+"),
|
||||
object: "HTMLCanvasElement",
|
||||
fakeGenerator: function(checker){
|
||||
return function toDataURL(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
||||
const fakeCanvas = getFakeCanvas(window, this, prefs);
|
||||
if (fakeCanvas !== this){
|
||||
notify("fakedReadout");
|
||||
}
|
||||
return original.apply(fakeCanvas, window.Array.from(args));
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
toBlob: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
if (!status.active && protectedPartChecker("input")){
|
||||
const contextType = canvasContextType.get(obj);
|
||||
status.active = contextType !== "2d";
|
||||
}
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout+"),
|
||||
object: "HTMLCanvasElement",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function toBlob(callback){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
||||
const fakeCanvas = getFakeCanvas(window, this, prefs);
|
||||
if (fakeCanvas !== this){
|
||||
notify("fakedReadout");
|
||||
}
|
||||
return original.apply(fakeCanvas, window.Array.from(args));
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
});
|
||||
if (this instanceof toBlob){
|
||||
throw new extension.getWrapped(window).TypeError(
|
||||
"HTMLCanvasElement.prototype.toBlob is not a constructor"
|
||||
);
|
||||
}
|
||||
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||
};
|
||||
},
|
||||
exportOptions: {allowCallbacks: true}
|
||||
},
|
||||
mozGetAsFile: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
if (!status.active && protectedPartChecker("input")){
|
||||
const contextType = canvasContextType.get(obj);
|
||||
status.active = contextType !== "2d";
|
||||
}
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout+"),
|
||||
object: "HTMLCanvasElement",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function mozGetAsFile(callback){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
||||
const fakeCanvas = getFakeCanvas(window, this, prefs);
|
||||
if (fakeCanvas !== this){
|
||||
notify("fakedReadout");
|
||||
}
|
||||
return original.apply(fakeCanvas, window.Array.from(args));
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
exportOptions: {allowCallbacks: true}
|
||||
},
|
||||
getImageData: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout"),
|
||||
object: "CanvasRenderingContext2D",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function getImageData(sx, sy, sw, sh){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
@ -434,10 +404,10 @@
|
||||
"2d"
|
||||
);
|
||||
}
|
||||
return original.apply(context, window.Array.from(args));
|
||||
return original.call(context, ...args);
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
return original.call(this, ...args);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -445,23 +415,21 @@
|
||||
},
|
||||
isPointInPath: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout"),
|
||||
object: "CanvasRenderingContext2D",
|
||||
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 originalValue = original.apply(this, window.Array.from(args));
|
||||
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;
|
||||
@ -472,32 +440,31 @@
|
||||
},
|
||||
isPointInStroke: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("readout");
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("readout"),
|
||||
object: "CanvasRenderingContext2D",
|
||||
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 originalValue = original.apply(this, window.Array.from(args));
|
||||
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;
|
||||
@ -508,104 +475,45 @@
|
||||
},
|
||||
fillText: {
|
||||
type: "input",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("input");
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("input"),
|
||||
object: "CanvasRenderingContext2D",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function fillText(str, x, y){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
||||
notify("fakedInput");
|
||||
let oldImageData;
|
||||
try {
|
||||
// "this" is not trustable - it may be not a context
|
||||
oldImageData = getImageData(window, this).imageData;
|
||||
}
|
||||
catch (error){
|
||||
// nothing to do here
|
||||
}
|
||||
// if "this" is not a correct context the next line will throw an error
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
const newImageData = getImageData(window, this).imageData;
|
||||
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, mixOnInputCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
strokeText: {
|
||||
type: "input",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker("input");
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus("input"),
|
||||
object: "CanvasRenderingContext2D",
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
return function strokeText(str, x, y){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
||||
notify("fakedInput");
|
||||
let oldImageData;
|
||||
try {
|
||||
// "this" is not trustable - it may be not a context
|
||||
oldImageData = getImageData(window, this).imageData;
|
||||
}
|
||||
catch (error){
|
||||
// nothing to do here
|
||||
}
|
||||
// if "this" is not a correct context the next line will throw an error
|
||||
const ret = original.apply(this, window.Array.from(args));
|
||||
const newImageData = getImageData(window, this).imageData;
|
||||
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, mixOnInputCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
readPixels: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker(["readout", "input"]);
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus(["readout", "input"]),
|
||||
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
|
||||
fakeGenerator: function(checker){
|
||||
// eslint-disable-next-line max-params, no-unused-vars
|
||||
// eslint-disable-next-line max-params
|
||||
return function readPixels(x, y, width, height, format, type, pixels){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
||||
notify("fakedReadout");
|
||||
const fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
|
||||
const {context} = copyCanvasToWebgl(
|
||||
const {context} = webgl.copyCanvasToWebgl(
|
||||
window,
|
||||
fakeCanvas,
|
||||
this instanceof window.WebGLRenderingContext? "webgl": "webgl2"
|
||||
);
|
||||
return original.apply(context, window.Array.from(args));
|
||||
return original.call(context, ...args);
|
||||
}
|
||||
else {
|
||||
return original.apply(this, window.Array.from(args));
|
||||
return original.call(this, ...args);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -613,59 +521,16 @@
|
||||
},
|
||||
getParameter: {
|
||||
type: "readout",
|
||||
getStatus: function(obj, status, prefs){
|
||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||
status = Object.create(status);
|
||||
status.active = protectedPartChecker(["readout", "input"]);
|
||||
return status;
|
||||
},
|
||||
getStatus: createGetStatus(["readout", "input"]),
|
||||
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
|
||||
fakeGenerator: function(checker){
|
||||
Object.keys(parameterChangeDefinition).forEach(function(parameterName){
|
||||
const definition = parameterChangeDefinition[parameterName];
|
||||
definition.pname = parameterName;
|
||||
if (!definition.fake){
|
||||
definition.fake = definition.isArray?
|
||||
function fake(originalValue, window){
|
||||
let faked = false;
|
||||
let fakedValue = [];
|
||||
for (let i = 0; i < originalValue.length; i += 1){
|
||||
fakedValue[i] = parameterFakeTypes[this.type](originalValue[i], this, window);
|
||||
faked |= originalValue[i] === fakedValue[i];
|
||||
originalValue[i] = fakedValue[i];
|
||||
}
|
||||
this.fake = function(originalValue){
|
||||
if (faked){
|
||||
for (let i = 0; i < originalValue.length; i += 1){
|
||||
originalValue[i] = fakedValue[i];
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: originalValue,
|
||||
faked
|
||||
};
|
||||
};
|
||||
return {
|
||||
value: originalValue,
|
||||
faked
|
||||
};
|
||||
}:
|
||||
function fake(originalValue, window){
|
||||
let value = parameterFakeTypes[this.type](originalValue, this, window);
|
||||
let faked = value === originalValue;
|
||||
this.fake = function(){
|
||||
return {value, faked};
|
||||
};
|
||||
return {value, faked};
|
||||
};
|
||||
}
|
||||
});
|
||||
webgl.initializeParameterDefinitions();
|
||||
return function getParameter(pname){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = original.apply(this, window.Array.from(args));
|
||||
if (parameterChangeDefinition[pname]){
|
||||
const definition = parameterChangeDefinition[pname];
|
||||
const originalValue = original.call(this, ...args);
|
||||
if (webgl.parameterChangeDefinition[pname]){
|
||||
const definition = webgl.parameterChangeDefinition[pname];
|
||||
const {value, faked} = definition.fake(originalValue, window, prefs);
|
||||
if (faked){
|
||||
notify("fakedReadout");
|
||||
@ -678,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";
|
||||
|
@ -12,7 +12,8 @@
|
||||
scope = require.register("./modifiedDOMRectAPI", {});
|
||||
}
|
||||
|
||||
const {getWrapped, checkerWrapper, setProperties: setProperties} = require("./modifiedAPIFunctions");
|
||||
const extension = require("./extension");
|
||||
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||
const {byteArrayToString: hash} = require("./hash");
|
||||
|
||||
|
||||
@ -30,7 +31,7 @@
|
||||
|
||||
const registeredRects = new WeakMap();
|
||||
function registerDOMRect(domRect, notify, window, prefs){
|
||||
registeredRects.set(getWrapped(domRect), {
|
||||
registeredRects.set(extension.getWrapped(domRect), {
|
||||
notify: function(){
|
||||
let done = false;
|
||||
return function(message){
|
||||
@ -45,47 +46,104 @@
|
||||
});
|
||||
}
|
||||
function getDOMRectRegistration(domRect){
|
||||
return registeredRects.get(getWrapped(domRect));
|
||||
return registeredRects.get(extension.getWrapped(domRect));
|
||||
}
|
||||
|
||||
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;
|
||||
const originalValue = args.length?
|
||||
original.call(this, ...args):
|
||||
original.call(this);
|
||||
registerDOMRect(originalValue, notify, window, prefs);
|
||||
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: {
|
||||
@ -94,7 +152,7 @@
|
||||
return function getClientRects(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = args.length? original.apply(this, window.Array.from(args)): original.call(this);
|
||||
const ret = args.length? original.call(this, ...args): original.call(this);
|
||||
for (let i = 0; i < ret.length; i += 1){
|
||||
registerDOMRect(ret[i], notify, window, prefs);
|
||||
}
|
||||
@ -107,52 +165,74 @@
|
||||
object: ["Range", "Element"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getBoundingClientRect(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = args.length? original.apply(this, window.Array.from(args)): original.call(this);
|
||||
registerDOMRect(ret, notify, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
};
|
||||
|
||||
}
|
||||
},
|
||||
getBounds: {
|
||||
object: ["DOMQuad"],
|
||||
getBoxQuads: {
|
||||
object: ["Document", "Element", "Text", "CSSPseudoElement"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getBounds(){
|
||||
return function getBoxQuads(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = args.length? original.apply(this, window.Array.from(args)): original.call(this);
|
||||
registerDOMRect(ret, notify, window, prefs);
|
||||
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){
|
||||
return function getBBox(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = args.length? original.apply(this, window.Array.from(args)): original.call(this);
|
||||
registerDOMRect(ret, notify, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
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){
|
||||
return function getBBox(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const ret = args.length? original.apply(this, window.Array.from(args)): original.call(this);
|
||||
registerDOMRect(ret, notify, window, prefs);
|
||||
return ret;
|
||||
});
|
||||
return function getExtentOfChar(){
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
getPointAtLength: {
|
||||
object: ["SVGGeometryElement", "SVGPathElement"],
|
||||
fakeGenerator: function(checker){
|
||||
return function getPointAtLength(){
|
||||
return checkerWrapper(checker, this, arguments, fakePointCallback);
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -166,12 +246,13 @@
|
||||
]:
|
||||
[
|
||||
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,
|
||||
getterGenerator: function(){
|
||||
const temp = eval(`({
|
||||
get ${property}(){
|
||||
const temp = {
|
||||
get [property](){
|
||||
const registration = getDOMRectRegistration(this);
|
||||
if (registration){
|
||||
return getFakeDomRect(
|
||||
@ -179,24 +260,24 @@
|
||||
this,
|
||||
registration.prefs,
|
||||
registration.notify
|
||||
).${property};
|
||||
)[property];
|
||||
}
|
||||
return this.${property};
|
||||
return this[property];
|
||||
}
|
||||
})`);
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, property).get;
|
||||
}
|
||||
};
|
||||
if (!readonly){
|
||||
changedGetter.setterGenerator = function(window, original, prefs){
|
||||
const temp = eval(`({
|
||||
set ${property}(newValue){
|
||||
const temp = {
|
||||
set [property](newValue){
|
||||
const registration = getDOMRectRegistration(this);
|
||||
if (registration){
|
||||
const fakeDomRect = getFakeDomRect(window, this, prefs, registration.notify);
|
||||
registeredRects.delete(getWrapped(this));
|
||||
registeredRects.delete(extension.getWrapped(this));
|
||||
["x", "y", "width", "height"].forEach((prop) => {
|
||||
if (prop === "${property}"){
|
||||
if (prop === property){
|
||||
this[prop] = newValue;
|
||||
}
|
||||
else {
|
||||
@ -205,10 +286,10 @@
|
||||
});
|
||||
}
|
||||
else {
|
||||
original.apply(this, window.Array.from(arguments));
|
||||
original.call(this, ...arguments);
|
||||
}
|
||||
}
|
||||
})`);
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, property).set;
|
||||
};
|
||||
}
|
||||
@ -234,14 +315,7 @@
|
||||
getterGenerator: function(checker){
|
||||
const temp = {
|
||||
get intersectionRect(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = args.length?
|
||||
original.apply(this, window.Array.from(args)):
|
||||
original.call(this);
|
||||
registerDOMRect(originalValue, notify, window, prefs);
|
||||
return originalValue;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
}
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, "intersectionRect").get;
|
||||
@ -257,14 +331,7 @@
|
||||
getterGenerator: function(checker){
|
||||
const temp = {
|
||||
get boundingClientRect(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = args.length?
|
||||
original.apply(this, window.Array.from(args)):
|
||||
original.call(this);
|
||||
registerDOMRect(originalValue, notify, window, prefs);
|
||||
return originalValue;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
}
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, "boundingClientRect").get;
|
||||
@ -280,14 +347,7 @@
|
||||
getterGenerator: function(checker){
|
||||
const temp = {
|
||||
get rootBounds(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = args.length?
|
||||
original.apply(this, window.Array.from(args)):
|
||||
original.call(this);
|
||||
registerDOMRect(originalValue, notify, window, prefs);
|
||||
return originalValue;
|
||||
});
|
||||
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||
}
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, "rootBounds").get;
|
||||
@ -295,15 +355,9 @@
|
||||
}
|
||||
];
|
||||
|
||||
function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs("protectDOMRect", status.url);
|
||||
return status;
|
||||
}
|
||||
|
||||
setProperties(scope.changedFunctions, scope.changedGetters, {
|
||||
type: "readout",
|
||||
getStatus: getStatus,
|
||||
getStatus: getStatusByFlag("protectDOMRect"),
|
||||
api: "domRect"
|
||||
});
|
||||
}());
|
@ -12,7 +12,7 @@
|
||||
scope = require.register("./modifiedHistoryAPI", {});
|
||||
}
|
||||
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const {checkerWrapper, setGetterProperties} = require("./modifiedAPIFunctions");
|
||||
|
||||
scope.changedGetters = [
|
||||
{
|
||||
@ -23,7 +23,7 @@
|
||||
get length(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalLength = original.apply(this, window.Array.from(args));
|
||||
const originalLength = original.call(this, ...args);
|
||||
const threshold = prefs("historyLengthThreshold", window.location);
|
||||
if (originalLength > threshold){
|
||||
notify("fakedHistoryReadout");
|
||||
@ -47,9 +47,9 @@
|
||||
return status;
|
||||
}
|
||||
|
||||
scope.changedGetters.forEach(function(changedGetter){
|
||||
changedGetter.type = "readout";
|
||||
changedGetter.getStatus = getStatus;
|
||||
changedGetter.api = "history";
|
||||
setGetterProperties(scope.changedGetters, {
|
||||
type: "readout",
|
||||
getStatus: getStatus,
|
||||
api: "history"
|
||||
});
|
||||
}());
|
@ -12,41 +12,85 @@
|
||||
scope = require.register("./modifiedNavigatorAPI", {});
|
||||
}
|
||||
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||
const extension = require("./extension");
|
||||
const navigator = require("./navigator");
|
||||
|
||||
let cookieStoreId = false;
|
||||
scope.setCookieStoreId = function(newCookieStoreId){
|
||||
if (typeof newCookieStoreId === "string"){
|
||||
cookieStoreId = (
|
||||
newCookieStoreId !== "" &&
|
||||
newCookieStoreId !== "firefox-default"
|
||||
)? newCookieStoreId: "";
|
||||
}
|
||||
};
|
||||
function getCookieStoreId(){
|
||||
while (cookieStoreId === false){
|
||||
extension.waitSync("to wait for cookie store id");
|
||||
}
|
||||
return cookieStoreId;
|
||||
}
|
||||
|
||||
scope.changedGetters = navigator.allProperties.map(function(property){
|
||||
return {
|
||||
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
|
||||
name: property,
|
||||
getterGenerator: function(checker){
|
||||
const temp = eval(`({
|
||||
get ${property}(){
|
||||
const temp = {
|
||||
get [property](){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {notify, window, original} = check;
|
||||
const originalValue = original.apply(this, window.Array.from(args));
|
||||
const returnValue = navigator.getNavigatorValue("${property}");
|
||||
const {notify, original} = check;
|
||||
const originalValue = original.call(this, ...args);
|
||||
const returnValue = navigator.getNavigatorValue(property, getCookieStoreId);
|
||||
if (originalValue !== returnValue){
|
||||
notify("fakedNavigatorReadout");
|
||||
}
|
||||
return returnValue;
|
||||
});
|
||||
}
|
||||
})`);
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, property).get;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs("protectNavigator", status.url);
|
||||
return status;
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.changedGetters.forEach(function(changedGetter){
|
||||
changedGetter.type = "readout";
|
||||
changedGetter.getStatus = getStatus;
|
||||
changedGetter.api = "navigator";
|
||||
setProperties(scope.changedFunctions, scope.changedGetters, {
|
||||
type: "readout",
|
||||
getStatus: getStatusByFlag("protectNavigator"),
|
||||
api: "navigator"
|
||||
});
|
||||
}());
|
88
lib/modifiedSVGAPI.js
Normal 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"
|
||||
});
|
||||
}());
|
@ -12,7 +12,7 @@
|
||||
scope = require.register("./modifiedScreenAPI", {});
|
||||
}
|
||||
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||
|
||||
const physical = {
|
||||
width: Math.round(window.screen.width * window.devicePixelRatio),
|
||||
@ -92,7 +92,7 @@
|
||||
function getFaker(dimension){
|
||||
return function fake(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = original.apply(this, window.Array.from(args));
|
||||
const originalValue = original.call(this, ...args);
|
||||
const returnValue = (typeof dimension) === "function"?
|
||||
dimension(window):
|
||||
dimension?
|
||||
@ -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;
|
||||
@ -206,11 +206,55 @@
|
||||
objectGetters: [function(window){return window.MediaQueryList && window.MediaQueryList.prototype;}],
|
||||
name: "matches",
|
||||
getterGenerator: function(checker){
|
||||
function getAlteredMedia(originalMedia, prefs, window){
|
||||
const dimensions = getScreenDimensions(prefs, window);
|
||||
return originalMedia.replace(
|
||||
/\(\s*(?:(min|max)-)?device-(width|height):\s+(\d+\.?\d*)px\s*\)/,
|
||||
function(m, type, dimension, value){
|
||||
value = parseFloat(value);
|
||||
let newCompareValue;
|
||||
switch (type){
|
||||
case "min":
|
||||
if (value <= dimensions[dimension]){
|
||||
newCompareValue = 0;
|
||||
}
|
||||
else {
|
||||
newCompareValue = 2 * physical[dimension];
|
||||
}
|
||||
break;
|
||||
case "max":
|
||||
if (value >= dimensions[dimension]){
|
||||
newCompareValue = 2 * physical[dimension];
|
||||
}
|
||||
else {
|
||||
newCompareValue = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (
|
||||
Math.round(value * 100) ===
|
||||
Math.round(dimensions[dimension] * 100)
|
||||
){
|
||||
newCompareValue = physical[dimension];
|
||||
}
|
||||
else {
|
||||
newCompareValue = 0;
|
||||
}
|
||||
}
|
||||
return "(" + (type? type + "-": "") +
|
||||
"device-" + dimension + ": " +
|
||||
(
|
||||
newCompareValue /
|
||||
window.devicePixelRatio
|
||||
) + "px)";
|
||||
}
|
||||
);
|
||||
}
|
||||
const temp = {
|
||||
get matches(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
const originalValue = original.apply(this, window.Array.from(args));
|
||||
const originalValue = original.call(this, ...args);
|
||||
const screenSize = prefs("screenSize", window.location);
|
||||
if (
|
||||
(
|
||||
@ -219,49 +263,8 @@
|
||||
) &&
|
||||
this.media.match(/device-(width|height)/)
|
||||
){
|
||||
const dimensions = getScreenDimensions(prefs, window);
|
||||
const originalMedia = this.media;
|
||||
const alteredMedia = this.media.replace(
|
||||
/\(\s*(?:(min|max)-)?device-(width|height):\s+(\d+\.?\d*)px\s*\)/,
|
||||
function(m, type, dimension, value){
|
||||
value = parseFloat(value);
|
||||
let newCompareValue = value;
|
||||
switch (type){
|
||||
case "min":
|
||||
if (value <= dimensions[dimension]){
|
||||
newCompareValue = 0;
|
||||
}
|
||||
else {
|
||||
newCompareValue = 2 * physical[dimension];
|
||||
}
|
||||
break;
|
||||
case "max":
|
||||
if (value >= dimensions[dimension]){
|
||||
newCompareValue = 2 * physical[dimension];
|
||||
}
|
||||
else {
|
||||
newCompareValue = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (
|
||||
Math.round(value * 100) ===
|
||||
Math.round(dimensions[dimension] * 100)
|
||||
){
|
||||
newCompareValue = physical[dimension];
|
||||
}
|
||||
else {
|
||||
newCompareValue = 0;
|
||||
}
|
||||
}
|
||||
return "(" + (type? type + "-": "") +
|
||||
"device-" + dimension + ": " +
|
||||
(
|
||||
newCompareValue /
|
||||
window.devicePixelRatio
|
||||
) + "px)";
|
||||
}
|
||||
);
|
||||
const alteredMedia = getAlteredMedia(originalMedia, prefs, window);
|
||||
if (alteredMedia !== originalMedia){
|
||||
const alteredQuery = window.matchMedia(alteredMedia);
|
||||
const fakedValue = original.call(alteredQuery);
|
||||
@ -280,15 +283,9 @@
|
||||
},
|
||||
];
|
||||
|
||||
function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs("protectScreen", status.url);
|
||||
return status;
|
||||
}
|
||||
|
||||
scope.changedGetters.forEach(function(changedGetter){
|
||||
changedGetter.type = "readout";
|
||||
changedGetter.getStatus = getStatus;
|
||||
changedGetter.api = "screen";
|
||||
setGetterProperties(scope.changedGetters, {
|
||||
type: "readout",
|
||||
getStatus: getStatusByFlag("protectScreen"),
|
||||
api: "screen"
|
||||
});
|
||||
}());
|
96
lib/modifiedTextMetricsAPI.js
Normal 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"
|
||||
});
|
||||
}());
|
@ -12,7 +12,7 @@
|
||||
scope = require.register("./modifiedWindowAPI", {});
|
||||
}
|
||||
|
||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||
|
||||
const windowNames = new WeakMap();
|
||||
scope.changedGetters = [
|
||||
@ -23,11 +23,8 @@
|
||||
const temp = {
|
||||
get opener(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (!prefs("protectWindow", window.location)){
|
||||
return original.apply(this, window.Array.from(args));
|
||||
}
|
||||
const originalOpener = original.apply(this, window.Array.from(args));
|
||||
const {notify, original} = check;
|
||||
const originalOpener = original.call(this, ...args);
|
||||
if (originalOpener !== null){
|
||||
notify("fakedWindowReadout");
|
||||
}
|
||||
@ -51,12 +48,15 @@
|
||||
const temp = {
|
||||
get name(){
|
||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||
const {prefs, notify, window, original} = check;
|
||||
if (!prefs("protectWindow", window.location)){
|
||||
return original.apply(this, window.Array.from(args));
|
||||
const {notify, original, prefs} = check;
|
||||
const originalName = original.call(this, ...args);
|
||||
if (
|
||||
this !== this.top &&
|
||||
prefs("allowWindowNameInFrames", this.location)
|
||||
){
|
||||
return originalName;
|
||||
}
|
||||
const originalName = original.apply(this, window.Array.from(args));
|
||||
const returnedName = windowNames.get(window) || "";
|
||||
const returnedName = windowNames.get(this) || "";
|
||||
if (originalName !== returnedName){
|
||||
notify("fakedWindowReadout");
|
||||
}
|
||||
@ -69,8 +69,8 @@
|
||||
setterGenerator: function(window, original){
|
||||
const temp = {
|
||||
set name(name){
|
||||
original.apply(this, window.Array.from(arguments));
|
||||
windowNames.set(window, name);
|
||||
original.call(this, ...arguments);
|
||||
windowNames.set(this, name);
|
||||
}
|
||||
};
|
||||
return Object.getOwnPropertyDescriptor(temp, "name").set;
|
||||
@ -78,15 +78,9 @@
|
||||
}
|
||||
];
|
||||
|
||||
function getStatus(obj, status, prefs){
|
||||
status = Object.create(status);
|
||||
status.active = prefs("protectWindow", status.url);
|
||||
return status;
|
||||
}
|
||||
|
||||
scope.changedGetters.forEach(function(changedGetter){
|
||||
changedGetter.type = "readout";
|
||||
changedGetter.getStatus = getStatus;
|
||||
changedGetter.api = "window";
|
||||
setGetterProperties(scope.changedGetters, {
|
||||
type: "readout",
|
||||
getStatus: getStatusByFlag("protectWindow"),
|
||||
api: "window"
|
||||
});
|
||||
}());
|
103
lib/navigator.js
@ -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 = {};
|
||||
|
||||
@ -36,38 +37,63 @@
|
||||
changedValues = newValue;
|
||||
});
|
||||
|
||||
|
||||
function getValue(name, stack = []){
|
||||
if (stack.indexOf(name) !== -1){
|
||||
return "[ERROR: loop in property definition]";
|
||||
}
|
||||
stack.push(name);
|
||||
|
||||
switch (name){
|
||||
case "original value":
|
||||
return original[stack[stack.length - 2]];
|
||||
case "random":
|
||||
return String.fromCharCode(Math.floor(65 + 85 * Math.random()));
|
||||
default:
|
||||
if (changedValues.hasOwnProperty(name)){
|
||||
return parseString(changedValues[name], stack.slice());
|
||||
const getValue = function(){
|
||||
function getChangedValues(getCookieStoreId){
|
||||
if (changedValues.contextualIdentities){
|
||||
const cookieStoreId = getCookieStoreId();
|
||||
if (
|
||||
cookieStoreId !== "" &&
|
||||
cookieStoreId !== "firefox-default" &&
|
||||
changedValues.contextualIdentities[cookieStoreId]
|
||||
){
|
||||
return changedValues.contextualIdentities[cookieStoreId];
|
||||
}
|
||||
else {
|
||||
return original[name];
|
||||
return changedValues;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return changedValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
function parseString(string, stack){
|
||||
if (string === "{undefined}"){
|
||||
return undefined;
|
||||
}
|
||||
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
|
||||
return getValue(name, stack.slice());
|
||||
});
|
||||
}
|
||||
|
||||
return function getValue(name, getCookieStoreId){
|
||||
const changedValues = getChangedValues(getCookieStoreId);
|
||||
|
||||
function getValueInternal(name, stack = []){
|
||||
if (stack.indexOf(name) !== -1){
|
||||
return "[ERROR: loop in property definition]";
|
||||
}
|
||||
stack.push(name);
|
||||
|
||||
switch (name){
|
||||
case "original value":
|
||||
return original[stack[stack.length - 2]];
|
||||
case "random":
|
||||
return String.fromCharCode(Math.floor(65 + 85 * Math.random()));
|
||||
default:
|
||||
if (changedValues.hasOwnProperty(name)){
|
||||
return parseString(changedValues[name], stack.slice());
|
||||
}
|
||||
else {
|
||||
return original[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
function parseString(string, stack){
|
||||
if (string === "{undefined}"){
|
||||
return undefined;
|
||||
}
|
||||
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
|
||||
return getValueInternal(name, stack.slice());
|
||||
});
|
||||
}
|
||||
return getValueInternal(name);
|
||||
};
|
||||
}();
|
||||
|
||||
scope.getNavigatorValue = function getNavigatorValue(name){
|
||||
return getValue(name);
|
||||
scope.getNavigatorValue = function getNavigatorValue(name, getCookieStoreId){
|
||||
return getValue(name, getCookieStoreId);
|
||||
};
|
||||
|
||||
function changeHTTPHeader(details){
|
||||
@ -82,7 +108,9 @@
|
||||
){
|
||||
for (let header of details.requestHeaders){
|
||||
if (header.name.toLowerCase() === "user-agent"){
|
||||
header.value = getValue("userAgent");
|
||||
header.value = getValue("userAgent", function(){
|
||||
return details.cookieStoreId;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,5 +146,24 @@
|
||||
scope.unregisterHeaderChange();
|
||||
}
|
||||
});
|
||||
|
||||
if (browser.contextualIdentities && browser.contextualIdentities.onRemoved){
|
||||
logging.message("register contextual navigator identities removal");
|
||||
browser.contextualIdentities.onRemoved.addListener(function(details){
|
||||
logging.message("Contextual navigator identity", details.contextualIdentity.cookieStoreId, "removed.");
|
||||
if (changedValues.contextualIdentities){
|
||||
delete changedValues.contextualIdentities[details.contextualIdentity.cookieStoreId];
|
||||
if (Object.keys(changedValues.contextualIdentities).length === 0){
|
||||
delete changedValues.contextualIdentities;
|
||||
}
|
||||
settings.navigatorDetails = changedValues;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
logging.error(
|
||||
"Old Firefox does not support browser.contextualIdentities.onRemoved"
|
||||
);
|
||||
}
|
||||
};
|
||||
}());
|
@ -163,16 +163,12 @@
|
||||
});
|
||||
};
|
||||
|
||||
settings.on("showNotifications", function({newValue}){
|
||||
settings.on("showNotifications", async function({newValue}){
|
||||
if (!newValue){
|
||||
logging.message("notifications were disabled -> hide all page actions");
|
||||
browser.tabs.query({}).then(function(tabs){
|
||||
tabs.forEach(function(tab){
|
||||
browser.pageAction.hide(tab.id);
|
||||
});
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to get browser tabs:", error);
|
||||
const tabs = await browser.tabs.query({});
|
||||
tabs.forEach(function(tab){
|
||||
browser.pageAction.hide(tab.id);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -180,20 +176,16 @@
|
||||
browser.tabs.onRemoved.addListener(function(tabId){
|
||||
tabsData.delete(tabId);
|
||||
});
|
||||
settings.on("displayBadge", function({newValue}){
|
||||
settings.on("displayBadge", async function({newValue}){
|
||||
if (!newValue){
|
||||
logging.message("badge was disabled -> hide all badges");
|
||||
if (browser.browserAction.setBadgeText){
|
||||
browser.tabs.query({}).then(function(tabs){
|
||||
tabs.forEach(function(tab){
|
||||
browser.browserAction.setBadgeText({
|
||||
tabId: tab.id,
|
||||
text: ""
|
||||
});
|
||||
const tabs = await browser.tabs.query({});
|
||||
tabs.forEach(function(tab){
|
||||
browser.browserAction.setBadgeText({
|
||||
tabId: tab.id,
|
||||
text: ""
|
||||
});
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to get browser tabs:", error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -89,23 +89,10 @@
|
||||
};
|
||||
}();
|
||||
|
||||
browser.windows.onRemoved.addListener(function(){
|
||||
browser.windows.getAll().then(function(windows){
|
||||
if (windows.every(function(window){
|
||||
return !window.incognito;
|
||||
})){
|
||||
clearIncognito();
|
||||
}
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to get browser windows:", error);
|
||||
});
|
||||
});
|
||||
|
||||
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.
|
||||
@ -117,28 +104,24 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
function broadcast(data){
|
||||
browser.tabs.query({}).then(function(tabs){
|
||||
tabs.forEach(function(tab){
|
||||
browser.tabs.sendMessage(tab.id, data);
|
||||
});
|
||||
return;
|
||||
}).catch(function(error){
|
||||
logging.warning("Unable to get browser tabs:", error);
|
||||
async function broadcast(data){
|
||||
const tabs = await browser.tabs.query({});
|
||||
tabs.forEach(function(tab){
|
||||
browser.tabs.sendMessage(tab.id, data);
|
||||
});
|
||||
}
|
||||
function clearIncognito(){
|
||||
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);
|
||||
@ -181,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);
|
||||
}
|
||||
}());
|
@ -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,24 +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){
|
||||
logging.message("Starting synchronous request to wait for cookie store id.");
|
||||
try {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "https://[::]", false);
|
||||
xhr.send();
|
||||
xhr = null;
|
||||
}
|
||||
catch (error){
|
||||
logging.verbose("Error in XHR:", error);
|
||||
}
|
||||
}
|
||||
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);
|
||||
@ -200,7 +205,7 @@
|
||||
return function getConstantPixelRng(length, window, ignoredColors){
|
||||
const rng = scope.nonPersistent.getValueRng(1024, window);
|
||||
|
||||
// eslint-disable-next-line max-params, no-unused-vars
|
||||
// eslint-disable-next-line max-params
|
||||
return function(r, g, b, a, i){
|
||||
const index = String.fromCharCode(r, g, b, a);
|
||||
if (ignoredColors[index]){
|
||||
|
@ -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){
|
||||
|
@ -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,77 +164,89 @@
|
||||
}
|
||||
};
|
||||
|
||||
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){
|
||||
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"
|
||||
);
|
||||
if (!scope.urlContainer){
|
||||
return;
|
||||
}
|
||||
scope.urlContainer.on(function({newValue, oldValue}){
|
||||
newValue.forEach(initializeUrlSetting);
|
||||
|
||||
const newUrls = newValue.map(function(entry){return entry.url;});
|
||||
const oldUrls = oldValue.map(function(entry){return entry.url;});
|
||||
const matching = {};
|
||||
newUrls.forEach(function(url, i){
|
||||
matching[url] = {new: i, old: oldUrls.indexOf(url)};
|
||||
});
|
||||
oldUrls.forEach(function(url, i){
|
||||
if (!matching[url]){
|
||||
matching[url] = {new: -1, old: i};
|
||||
}
|
||||
});
|
||||
Object.keys(matching).forEach(function(url){
|
||||
const oldEntry = oldValue[matching[url].old] || {};
|
||||
const newEntry = newValue[matching[url].new] || {};
|
||||
scope.urlContainer.entries.forEach(function(settingDefinition){
|
||||
const name = settingDefinition.name;
|
||||
const oldValue = oldEntry[name];
|
||||
const newValue = newEntry[name];
|
||||
|
||||
if (oldValue !== newValue){
|
||||
((eventHandler[name] || {})[url] || []).forEach(function(callback){
|
||||
callback({name, newValue, oldValue, url});
|
||||
});
|
||||
}
|
||||
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
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const newUrls = newValue.map(function(entry){return entry.url;});
|
||||
const oldUrls = oldValue.map(function(entry){return entry.url;});
|
||||
const matching = {};
|
||||
newUrls.forEach(function(url, i){
|
||||
matching[url] = {new: i, old: oldUrls.indexOf(url)};
|
||||
});
|
||||
oldUrls.forEach(function(url, i){
|
||||
if (!matching[url]){
|
||||
matching[url] = {new: -1, old: i};
|
||||
}
|
||||
});
|
||||
Object.keys(matching).forEach(function(url){
|
||||
const oldEntry = oldValue[matching[url].old] || {};
|
||||
const newEntry = newValue[matching[url].new] || {};
|
||||
scope.urlContainer.entries.forEach(function(settingDefinition){
|
||||
const name = settingDefinition.name;
|
||||
const oldValue = oldEntry[name];
|
||||
const newValue = newEntry[name];
|
||||
|
||||
if (oldValue !== newValue){
|
||||
((eventHandler[name] || {})[url] || []).forEach(function(callback){
|
||||
callback({name, newValue, oldValue, url});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}());
|
@ -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
|
||||
},
|
||||
@ -321,6 +348,11 @@
|
||||
defaultValue: false,
|
||||
urlSpecific: true
|
||||
},
|
||||
{
|
||||
name: "allowWindowNameInFrames",
|
||||
defaultValue: false,
|
||||
urlSpecific: true
|
||||
},
|
||||
{
|
||||
name: "protectDOMRect",
|
||||
defaultValue: true,
|
||||
@ -330,6 +362,16 @@
|
||||
name: "domRectIntegerFactor",
|
||||
defaultValue: 4
|
||||
},
|
||||
{
|
||||
name: "protectSVG",
|
||||
defaultValue: true,
|
||||
urlSpecific: true
|
||||
},
|
||||
{
|
||||
name: "protectTextMetrics",
|
||||
defaultValue: true,
|
||||
urlSpecific: true
|
||||
},
|
||||
{
|
||||
name: "blockDataURLs",
|
||||
defaultValue: true,
|
||||
@ -373,17 +415,30 @@
|
||||
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
|
||||
},
|
||||
{
|
||||
name: "storageVersion",
|
||||
defaultValue: 0.6,
|
||||
defaultValue: 1.0,
|
||||
fixed: true
|
||||
}
|
||||
];
|
||||
|
@ -16,40 +16,40 @@
|
||||
|
||||
scope.getMessages = function(settingDefinition){
|
||||
const messages = [];
|
||||
if (settingDefinition){
|
||||
messages.push(settingDefinition.name + "_title");
|
||||
messages.push(settingDefinition.name + "_description");
|
||||
if (settingDefinition.urlSpecific){
|
||||
messages.push(settingDefinition.name + "_urlSpecific");
|
||||
}
|
||||
if (settingDefinition.options){
|
||||
settingDefinition.options.forEach(function(option){
|
||||
if (option !== null){
|
||||
messages.push(settingDefinition.name + "_options." + option);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settingDefinition.inputs){
|
||||
settingDefinition.inputs.forEach(function(input){
|
||||
if (input){
|
||||
if (input.options){
|
||||
input.options.forEach(function(option){
|
||||
if (option !== null){
|
||||
messages.push(input.name + "_options." + option);
|
||||
}
|
||||
});
|
||||
if (!settingDefinition){
|
||||
return messages;
|
||||
}
|
||||
|
||||
messages.push(settingDefinition.name + "_title");
|
||||
messages.push(settingDefinition.name + "_description");
|
||||
if (settingDefinition.urlSpecific){
|
||||
messages.push(settingDefinition.name + "_urlSpecific");
|
||||
}
|
||||
if (settingDefinition.options){
|
||||
settingDefinition.options.forEach(function(option){
|
||||
if (option !== null){
|
||||
messages.push(settingDefinition.name + "_options." + option);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settingDefinition.inputs){
|
||||
settingDefinition.inputs.forEach(function(input){
|
||||
if (input && input.options){
|
||||
input.options.forEach(function(option){
|
||||
if (option !== null){
|
||||
messages.push(input.name + "_options." + option);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settingDefinition.action){
|
||||
messages.push(settingDefinition.name + "_label");
|
||||
}
|
||||
if (settingDefinition.actions){
|
||||
settingDefinition.actions.forEach(function(action){
|
||||
messages.push(action.name + "_label");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (settingDefinition.action){
|
||||
messages.push(settingDefinition.name + "_label");
|
||||
}
|
||||
if (settingDefinition.actions){
|
||||
settingDefinition.actions.forEach(function(action){
|
||||
messages.push(action.name + "_label");
|
||||
});
|
||||
}
|
||||
return messages;
|
||||
};
|
||||
|
@ -13,6 +13,7 @@
|
||||
}
|
||||
|
||||
const logging = require("./logging");
|
||||
const extension = require("./extension");
|
||||
const settingDefinitions = require("./settingDefinitions");
|
||||
const settingContainers = require("./settingContainers");
|
||||
const definitionsByName = {};
|
||||
@ -129,24 +130,24 @@
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const storeValue = function storeValue(newValue){
|
||||
const storeValue = async function storeValue(newValue){
|
||||
logging.verbose("Trying to store new value for %s", name, newValue);
|
||||
settings[name] = newValue;
|
||||
if (!settingDefinition.transient){
|
||||
const storeObject = {};
|
||||
storeObject[name] = newValue;
|
||||
const promise = browser.storage.local.set(storeObject);
|
||||
promise.then(function(){
|
||||
try {
|
||||
await browser.storage.local.set(storeObject);
|
||||
logging.verbose("New value stored for %s:", name, newValue);
|
||||
return;
|
||||
}).catch(function(error){
|
||||
}
|
||||
catch (error){
|
||||
logging.error("Unable to store new value for %s:", name, newValue, error);
|
||||
});
|
||||
return promise;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
logging.warning("Transient setting %s cannot be stored.", name);
|
||||
return Promise.reject("Transient setting " + name + " cannot be stored.");
|
||||
throw "Transient setting " + name + " cannot be stored.";
|
||||
}
|
||||
};
|
||||
|
||||
@ -450,16 +451,7 @@
|
||||
};
|
||||
scope.forceLoad = function(){
|
||||
while (settings.isStillDefault){
|
||||
logging.message("Starting synchronous request to wait for settings.");
|
||||
try {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "https://[::]", false);
|
||||
xhr.send();
|
||||
xhr = null;
|
||||
}
|
||||
catch (error){
|
||||
logging.verbose("Error in XHR:", error);
|
||||
}
|
||||
extension.waitSync("to wait for settings");
|
||||
logging.message("settings still default?", settings.isStillDefault);
|
||||
}
|
||||
};
|
||||
|
@ -15,12 +15,11 @@
|
||||
|
||||
const settingDefinitions = require("./settingDefinitions");
|
||||
|
||||
scope.validVersions = [undefined, 0.1, 0.2, 0.3, 0.4, 0.5];
|
||||
scope.validVersions = [undefined, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1.0];
|
||||
scope.transitions = {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
"": function(oldStorage){
|
||||
"": function(){
|
||||
return {
|
||||
storageVersion: 0.6
|
||||
storageVersion: 1.0
|
||||
};
|
||||
},
|
||||
0.1: function(oldStorage){
|
||||
@ -42,43 +41,28 @@
|
||||
};
|
||||
|
||||
const urlSettings = {};
|
||||
|
||||
(oldStorage.blackList || "").split(",")
|
||||
.map(function(url){return url.trim();})
|
||||
.filter(function(url){return !!url;})
|
||||
.forEach(function(url){
|
||||
let entry = urlSettings[url];
|
||||
if (!entry){
|
||||
entry = {url, blockMode: "block"};
|
||||
urlSettings[url] = entry;
|
||||
newStorage.urlSettings.push(entry);
|
||||
}
|
||||
});
|
||||
(oldStorage.whiteList || "").split(",")
|
||||
.map(function(url){return url.trim();})
|
||||
.filter(function(url){return !!url;})
|
||||
.forEach(function(url){
|
||||
let entry = urlSettings[url];
|
||||
if (!entry){
|
||||
entry = {url, blockMode: "allow"};
|
||||
urlSettings[url] = entry;
|
||||
newStorage.urlSettings.push(entry);
|
||||
}
|
||||
});
|
||||
(oldStorage.ignoreList || "").split(",")
|
||||
.map(function(url){return url.trim();})
|
||||
.filter(function(url){return !!url;})
|
||||
.forEach(function(url){
|
||||
let entry = urlSettings[url];
|
||||
if (!entry){
|
||||
entry = {url, showNotifications: false};
|
||||
urlSettings[url] = entry;
|
||||
newStorage.urlSettings.push(entry);
|
||||
}
|
||||
else {
|
||||
entry.showNotifications = false;
|
||||
}
|
||||
});
|
||||
|
||||
[
|
||||
{listName: "blackList", property: "blockMode", value: "block"},
|
||||
{listName: "whiteList", property: "blockMode", value: "allow"},
|
||||
{listName: "ignoreList", property: "showNotifications", value: false}
|
||||
].forEach(function(listAction){
|
||||
(oldStorage[listAction.listName] || "").split(",")
|
||||
.map(function(url){return url.trim();})
|
||||
.filter(function(url){return !!url;})
|
||||
.forEach(function(url){
|
||||
let entry = urlSettings[url];
|
||||
if (!entry){
|
||||
entry = {url, [listAction.property]: listAction.value};
|
||||
urlSettings[url] = entry;
|
||||
newStorage.urlSettings.push(entry);
|
||||
}
|
||||
else {
|
||||
entry[listAction.property] = listAction.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
["whiteList", "blackList", "ignoreList"].forEach(function(list){
|
||||
if (oldStorage.hasOwnProperty(list)){
|
||||
newStorage[list] = "";
|
||||
@ -158,6 +142,25 @@
|
||||
}
|
||||
return newStorage;
|
||||
},
|
||||
0.6: function (oldStorage){
|
||||
const newStorage = {
|
||||
storageVersion: 1.0
|
||||
};
|
||||
if (
|
||||
oldStorage.hasOwnProperty("protectWindow") &&
|
||||
oldStorage.protectWindow &&
|
||||
oldStorage.hasOwnProperty("urlSettings") &&
|
||||
Array.isArray(oldStorage.urlSettings) &&
|
||||
oldStorage.urlSettings.filter(function(entry){
|
||||
return entry.url === "^https://www\\.google\\.com/recaptcha/api2/(?:b?frame|anchor).*$";
|
||||
}).some(function(entry){
|
||||
return entry.protectWindow === false;
|
||||
})
|
||||
){
|
||||
newStorage.allowWindowNameInFrames = true;
|
||||
}
|
||||
return newStorage;
|
||||
}
|
||||
};
|
||||
|
||||
scope.check = function(storage, {settings, logging}){
|
||||
|
@ -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`;
|
||||
|
159
lib/webgl.js
@ -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");
|
||||
@ -109,4 +109,153 @@
|
||||
|
||||
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}){
|
||||
const bitLength = Math.floor(Math.log2(max) + 1);
|
||||
const rng = randomSupply.getBitRng(bitLength, window);
|
||||
let value = 0;
|
||||
for (let i = 0; i < bitLength; i += 1){
|
||||
value <<= 1;
|
||||
value ^= rng(originalValue, index + i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
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){
|
||||
const int = Math.floor(originalValue);
|
||||
if (int !== originalValue){
|
||||
const decimal = originalValue - int;
|
||||
const rng = randomSupply.getRng(1, window);
|
||||
const newDecimal = decimal * (rng(definition.pname) / 0xFFFFFFFF);
|
||||
return int + newDecimal;
|
||||
}
|
||||
else {
|
||||
return originalValue;
|
||||
}
|
||||
},
|
||||
shift: function(originalValue, definition, window){
|
||||
const value = getNumber({originalValue, max: definition.max, index: definition.pname, window});
|
||||
return originalValue >>> value;
|
||||
},
|
||||
"-": function(originalValue, definition, window){
|
||||
const value = getNumber({originalValue, max: definition.max, index: definition.pname, window}) *
|
||||
(definition.factor || 1);
|
||||
if (value > originalValue){
|
||||
return 0;
|
||||
}
|
||||
return originalValue - value;
|
||||
}
|
||||
};
|
||||
const parameterChangeDefinition = {
|
||||
2928: {name: "DEPTH_RANGE", type: "decimal", isArray: true},
|
||||
3379: {name: "MAX_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
3386: {name: "MAX_VIEWPORT_DIMS", type: "shift", max: 1, isArray: true},
|
||||
32883: {name: "MAX_3D_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
33000: {name: "MAX_ELEMENTS_VERTICES", type: "-", max: 3, factor: 50},
|
||||
33001: {name: "MAX_ELEMENTS_INDICES", type: "-", max: 3, factor: 50},
|
||||
33901: {name: "ALIASED_POINT_SIZE_RANGE", type: "decimal", isArray: true},
|
||||
33902: {name: "ALIASED_LINE_WIDTH_RANGE", type: "decimal", isArray: true},
|
||||
34024: {name: "MAX_RENDERBUFFER_SIZE", type: "shift", max: 1},
|
||||
34045: {name: "MAX_TEXTURE_LOD_BIAS", type: "-", max: 1, factor: 1},
|
||||
34076: {name: "MAX_CUBE_MAP_TEXTURE_SIZE", type: "shift", max: 1},
|
||||
34921: {name: "MAX_VERTEX_ATTRIBS", type: "shift", max: 1},
|
||||
34930: {name: "MAX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
||||
35071: {name: "MAX_ARRAY_TEXTURE_LAYERS", type: "shift", max: 1},
|
||||
35371: {name: "MAX_VERTEX_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
||||
35373: {name: "MAX_FRAGMENT_UNIFORM_BLOCKS", type: "-", max: 1, factor: 1},
|
||||
35374: {name: "MAX_COMBINED_UNIFORM_BLOCKS", type: "-", max: 3, factor: 1},
|
||||
35375: {name: "MAX_UNIFORM_BUFFER_BINDINGS", type: "-", max: 3, factor: 1},
|
||||
35376: {name: "MAX_UNIFORM_BLOCK_SIZE", type: "shift", max: 1},
|
||||
35377: {name: "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
||||
35379: {name: "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", type: "-", max: 7, factor: 10},
|
||||
35657: {name: "MAX_FRAGMENT_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
||||
35658: {name: "MAX_VERTEX_UNIFORM_COMPONENTS", type: "shift", max: 1},
|
||||
35659: {name: "MAX_VARYING_COMPONENTS", type: "shift", max: 1},
|
||||
35660: {name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS", type: "shift", max: 1},
|
||||
35661: {name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS", type: "-", max: 1, factor: 2},
|
||||
35968: {name: "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", type: "shift", max: 1},
|
||||
35978: {name: "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", type: "shift", max: 1},
|
||||
36203: {name: "MAX_ELEMENT_INDEX", type: "-", max: 15, factor: 1},
|
||||
36347: {name: "MAX_VERTEX_UNIFORM_VECTORS", type: "shift", max: 1},
|
||||
36348: {name: "MAX_VARYING_VECTORS", type: "shift", max: 1},
|
||||
36349: {name: "MAX_FRAGMENT_UNIFORM_VECTORS", type: "shift", max: 1},
|
||||
37154: {name: "MAX_VERTEX_OUTPUT_COMPONENTS", type: "shift", max: 1},
|
||||
37157: {name: "MAX_FRAGMENT_INPUT_COMPONENTS", type: "shift", max: 1},
|
||||
7936: {name: "VENDOR", type: "preference", preferenceName: "webGLVendor"},
|
||||
7937: {name: "RENDERER", type: "preference", preferenceName: "webGLRenderer"},
|
||||
37445: {name: "UNMASKED_VENDOR_WEBGL", type: "preference", preferenceName: "webGLUnmaskedVendor"},
|
||||
37446: {name: "UNMASKED_RENDERER_WEBGL", type: "preference", preferenceName: "webGLUnmaskedRenderer"}
|
||||
};
|
||||
|
||||
scope.initializeParameterDefinitions = function(){
|
||||
function singleFake(originalValue, window, prefs){
|
||||
const value = parameterFakeTypes[this.type](originalValue, this, window, prefs);
|
||||
const faked = value !== originalValue;
|
||||
this.fake = function(){
|
||||
return {value, faked};
|
||||
};
|
||||
return {value, faked};
|
||||
}
|
||||
function arrayFake(originalValue, window, prefs){
|
||||
let faked = false;
|
||||
let fakedValue = [];
|
||||
for (let i = 0; i < originalValue.length; i += 1){
|
||||
fakedValue[i] = parameterFakeTypes[this.type](originalValue[i], this, window, prefs);
|
||||
faked = faked || originalValue[i] !== fakedValue[i];
|
||||
originalValue[i] = fakedValue[i];
|
||||
}
|
||||
this.fake = function(originalValue){
|
||||
if (faked){
|
||||
for (let i = 0; i < originalValue.length; i += 1){
|
||||
originalValue[i] = fakedValue[i];
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: originalValue,
|
||||
faked
|
||||
};
|
||||
};
|
||||
return {
|
||||
value: originalValue,
|
||||
faked
|
||||
};
|
||||
}
|
||||
Object.keys(parameterChangeDefinition).forEach(function(parameterName){
|
||||
const definition = parameterChangeDefinition[parameterName];
|
||||
definition.pname = parameterName;
|
||||
if (!definition.fake){
|
||||
definition.fake = definition.isArray? arrayFake: singleFake;
|
||||
}
|
||||
});
|
||||
};
|
||||
scope.parameterChangeDefinition = parameterChangeDefinition;
|
||||
}());
|
173
lib/webglRandom.js
Normal 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",
|
||||
]
|
||||
},
|
||||
];
|
||||
}());
|