Compare commits
371 Commits
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 | ||
|
762367a87b | ||
|
a181780020 | ||
|
b7ba5c2050 | ||
|
5020e0b070 | ||
|
c62ddcc33f | ||
|
59ad6fc7d6 | ||
|
1aff68d802 | ||
|
635cdf8061 | ||
|
16fc49eee3 | ||
|
afd9aea767 | ||
|
17349dcb05 | ||
|
aef6bd3d59 | ||
|
b5e6d049ce | ||
|
83a8234b24 | ||
|
d4ce6c4b4b | ||
|
cded4d369a | ||
|
d930de1883 | ||
|
a555f3cd64 | ||
|
d42a4d2372 | ||
|
cc776b48de | ||
|
1430b89d55 | ||
|
320dc02941 | ||
|
5d6c2d9a47 | ||
|
73657852d3 | ||
|
ee254b3b93 | ||
|
f010c7c8fa | ||
|
aa7a4e1d06 | ||
|
64d4aa3f73 | ||
|
506f062c07 | ||
|
f3d1ca80f5 | ||
|
069165e8d6 | ||
|
5a355284f3 | ||
|
14b4bd8ac6 | ||
|
acc171041d | ||
|
a95fae3de8 | ||
|
d666d68812 |
6
.codebeatsettings
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"JAVASCRIPT": {
|
||||||
|
"LOC": [80, 90, 100, 120],
|
||||||
|
"BLOCK_NESTING": [4, 5, 6, 7]
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,22 @@
|
|||||||
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.
|
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)
|
<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.
|
privacy.resistFingerprinting kann aber problemlos aktiviert werden und der Fingerprinting-Schutz muss nicht deaktiviert werden.
|
||||||
|
|
||||||
|
Beschützte "Fingerprinting"-APIs:
|
||||||
|
<ul>
|
||||||
|
<li>canvas 2d</li>
|
||||||
|
<li>webGL</li>
|
||||||
|
<li>audio</li>
|
||||||
|
<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>
|
||||||
|
|
||||||
Nähere Informationen zum Fingerprinting können Sie finden auf:
|
Nähere Informationen zum Fingerprinting können Sie finden auf:
|
||||||
<ul>
|
<ul>
|
||||||
@ -27,17 +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 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>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>
|
<li>alles erlauben: Ignoriere alle Listen und erlaube die beschützten APIs auf allen Webseiten.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Beschützte "Fingerprinting"-APIs:
|
|
||||||
<ul>
|
|
||||||
<li>canvas 2d</li>
|
|
||||||
<li>webGL</li>
|
|
||||||
<li>audio</li>
|
|
||||||
<li>history</li>
|
|
||||||
<li>window (standardmäßig deaktiviert)</li>
|
|
||||||
<li>DOMRect</li>
|
|
||||||
<li>navigator (standardmäßig deaktiviert)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Falls Sie Fehler finden oder Verbesserungsvorschläge haben, teilen Sie mir das bitte auf https://github.com/kkapsner/CanvasBlocker/issues mit.
|
|
@ -1,7 +1,22 @@
|
|||||||
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.
|
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)
|
<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 is fine.
|
But setting privacy.resistFingerprinting to true and/or using the new fingerprinting protection introduced with Firefox 67 is fine.
|
||||||
|
|
||||||
|
Protected "fingerprinting" APIs:
|
||||||
|
<ul>
|
||||||
|
<li>canvas 2d</li>
|
||||||
|
<li>webGL</li>
|
||||||
|
<li>audio</li>
|
||||||
|
<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>
|
||||||
|
|
||||||
More information on fingerprinting can be found at:
|
More information on fingerprinting can be found at:
|
||||||
<ul>
|
<ul>
|
||||||
@ -29,16 +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> 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>
|
<li> allow everything: Ignore all lists and allow the protected APIs on all websites.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Protected "fingerprinting" APIs:
|
|
||||||
<ul>
|
|
||||||
<li>canvas 2d</li>
|
|
||||||
<li>webGL</li>
|
|
||||||
<li>audio</li>
|
|
||||||
<li>history</li>
|
|
||||||
<li>window (disabled by default)</li>
|
|
||||||
<li>DOMRect</li>
|
|
||||||
<li>navigator (disabled by default)</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.
|
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
!/.tools
|
129
.eslintrc.json
@ -1,40 +1,93 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"commonjs": true,
|
"commonjs": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"webextensions": true
|
"webextensions": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaFeatures": {
|
"ecmaVersion": 8,
|
||||||
"jsx": true
|
"ecmaFeatures": {
|
||||||
},
|
"jsx": true
|
||||||
"sourceType": "script"
|
},
|
||||||
},
|
"sourceType": "script"
|
||||||
"extends": "eslint:recommended",
|
},
|
||||||
"globals": {
|
"plugins": [
|
||||||
"exportFunction": false
|
"promise",
|
||||||
},
|
"eslint-comments",
|
||||||
"rules": {
|
"html"
|
||||||
"brace-style": ["error", "stroustrup", {"allowSingleLine": true}],
|
],
|
||||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
"extends": [
|
||||||
"constructor-super": "warn",
|
"eslint:recommended",
|
||||||
"eqeqeq": "error",
|
"plugin:promise/recommended",
|
||||||
"max-len": ["warn", {"code": 120, "tabWidth": 4}],
|
"plugin:eslint-comments/recommended"
|
||||||
"max-lines": ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}],
|
],
|
||||||
"max-params": ["warn", 4],
|
"globals": {
|
||||||
"no-const-assign": "warn",
|
"exportFunction": false
|
||||||
"no-this-before-super": "warn",
|
},
|
||||||
"no-undef": "error",
|
"rules": {
|
||||||
"no-unreachable": "warn",
|
"brace-style": ["error", "stroustrup", {"allowSingleLine": true}],
|
||||||
"no-unused-vars": "off",
|
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||||
"no-trailing-spaces": ["error", {"skipBlankLines": true}],
|
"complexity": ["warn", 20],
|
||||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
"consistent-return": "error",
|
||||||
"indent": ["error", "tab", {"SwitchCase": 1}],
|
"constructor-super": "warn",
|
||||||
"space-in-parens": ["error", "never"],
|
"eqeqeq": "error",
|
||||||
"valid-typeof": "warn",
|
"eslint-comments/no-use": ["error", {"allow": ["eslint-disable-next-line", "globals"]}],
|
||||||
"quotes": ["error", "double"],
|
"indent": ["error", "tab", {"SwitchCase": 1}],
|
||||||
"semi": ["error", "always"],
|
"max-depth": ["warn", 4],
|
||||||
"strict": ["error", "function"]
|
"max-len": ["warn", {"code": 120, "tabWidth": 4}],
|
||||||
}
|
"max-lines-per-function": ["warn", {"max": 80,"skipBlankLines": true, "skipComments": true}],
|
||||||
|
"max-lines": ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}],
|
||||||
|
"max-params": ["warn", 4],
|
||||||
|
"no-console": "error",
|
||||||
|
"no-const-assign": "error",
|
||||||
|
"no-inner-declarations": "warn",
|
||||||
|
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"no-this-before-super": "warn",
|
||||||
|
"no-trailing-spaces": ["error", {"skipBlankLines": true}],
|
||||||
|
"no-undef": "error",
|
||||||
|
"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"],
|
||||||
|
"valid-typeof": "warn"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["detectionTest.js", "modifiedCanvasAPI.js", "options.js", "settingsDisplay.js"],
|
||||||
|
"rules": {
|
||||||
|
"max-lines": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["test/*"],
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [".tools/*.js"],
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.html", "*.php"],
|
||||||
|
"rules": {
|
||||||
|
"no-useless-escape": "off",
|
||||||
|
"no-undef": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
18
.github/ISSUE_TEMPLATE.md
vendored
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
<!--- Provide a more detailed introduction to the issue itself. -->
|
<!--- 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 describing a bug, tell us what should happen. -->
|
||||||
<!--- If you're suggesting a change/improvement, tell us how it should work. -->
|
<!--- 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 describing a bug, tell us what happens instead of the expected behavior. -->
|
||||||
<!--- If suggesting a change/improvement, explain the difference from current behavior. -->
|
<!--- If suggesting a change/improvement, explain the difference from current behavior. -->
|
||||||
|
|
||||||
@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
## Steps to Reproduce (for bugs)
|
## Steps to Reproduce (for bugs)
|
||||||
<!--- Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. -->
|
<!--- Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. -->
|
||||||
1.
|
1. create a fresh Firefox profile
|
||||||
2.
|
2.
|
||||||
3.
|
3.
|
||||||
4.
|
4.
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||||
@ -36,6 +36,8 @@
|
|||||||
* Installed addons:
|
* Installed addons:
|
||||||
|
|
||||||
## Your Settings
|
## Your Settings
|
||||||
|
~~~ json
|
||||||
<!--- Copy your CanvasBlocker settings here. -->
|
<!--- Copy your CanvasBlocker settings here. -->
|
||||||
<!-- They can be retrieved by checking the expert mode and going to export settings. -->
|
<!-- 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". -->
|
||||||
|
~~~
|
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
printed.png
|
printed.png
|
||||||
web-ext-artifacts/
|
web-ext-artifacts/
|
||||||
versions/*.xpi
|
versions/*.xpi
|
||||||
|
node_modules/
|
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);
|
||||||
|
|
@ -7,6 +7,8 @@ const la = require("../_locales/" + language + "/messages.json");
|
|||||||
const laKeys = Object.keys(la);
|
const laKeys = Object.keys(la);
|
||||||
|
|
||||||
enKeys.forEach(function(key){
|
enKeys.forEach(function(key){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
if (en[key].message){
|
if (en[key].message){
|
||||||
if (!la[key] || !la[key].message){
|
if (!la[key] || !la[key].message){
|
||||||
console.log(key, "missing");
|
console.log(key, "missing");
|
||||||
|
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)"
|
||||||
|
]
|
@ -5,6 +5,8 @@ const util = require("util");
|
|||||||
|
|
||||||
|
|
||||||
function getMessagesInContent(content){
|
function getMessagesInContent(content){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const foundMessages = [];
|
const foundMessages = [];
|
||||||
[
|
[
|
||||||
/\b(?:_|browser.i18n.getMessage|extension.getTranslation|notify|extension)\(["']([^"']+)["']\s*(?:\)|,)/g,
|
/\b(?:_|browser.i18n.getMessage|extension.getTranslation|notify|extension)\(["']([^"']+)["']\s*(?:\)|,)/g,
|
||||||
@ -19,58 +21,57 @@ function getMessagesInContent(content){
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getMessagesInFile(path){
|
async function getMessagesInFile(path){
|
||||||
return await util.promisify(fs.exists)(path)
|
"use strict";
|
||||||
.then(function(exists){
|
|
||||||
if (exists){
|
const exists = await util.promisify(fs.exists)(path);
|
||||||
return util.promisify(fs.readFile)(path, {encoding: "UTF-8"})
|
if (exists){
|
||||||
.then(function(content){
|
const content = await util.promisify(fs.readFile)(path, {encoding: "UTF-8"});
|
||||||
return getMessagesInContent(content);
|
return getMessagesInContent(content);
|
||||||
});
|
}
|
||||||
}
|
else {
|
||||||
else {
|
console.log("file does not exist:", path);
|
||||||
console.log("file does not exist:", path);
|
return [];
|
||||||
return [];
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMessagesInFolder(folder){
|
async function getMessagesInFolder(folder){
|
||||||
return await util.promisify(fs.readdir)(folder, {encoding: "UTF-8"})
|
"use strict";
|
||||||
.then(function(files){
|
|
||||||
return Promise.all(
|
const files = await util.promisify(fs.readdir)(folder, {encoding: "UTF-8"});
|
||||||
files.filter(function(file){
|
|
||||||
return !file.startsWith(".");
|
const messages = await Promise.all(
|
||||||
}).map(function(file){
|
files.filter(function(file){
|
||||||
return path.join(folder, file);
|
return !file.startsWith(".");
|
||||||
}).map(function(path){
|
}).map(function(file){
|
||||||
return util.promisify(fs.stat)(path).then(function(stat){
|
return path.join(folder, file);
|
||||||
if (stat.isDirectory()){
|
}).map(async function(path){
|
||||||
return getMessagesInFolder(path);
|
const stat = await util.promisify(fs.stat)(path);
|
||||||
}
|
if (stat.isDirectory()){
|
||||||
else {
|
return getMessagesInFolder(path);
|
||||||
if (path.endsWith(".js")){
|
}
|
||||||
return getMessagesInFile(path);
|
else {
|
||||||
}
|
if (path.endsWith(".js")){
|
||||||
else {
|
return getMessagesInFile(path);
|
||||||
return [];
|
}
|
||||||
}
|
else {
|
||||||
}
|
return [];
|
||||||
});
|
}
|
||||||
})
|
}
|
||||||
).then(function(messages){
|
})
|
||||||
const flat = [];
|
);
|
||||||
messages.forEach(function(messages){
|
const flat = [];
|
||||||
messages.forEach(function(message){
|
messages.forEach(function(messages){
|
||||||
flat.push(message);
|
messages.forEach(function(message){
|
||||||
});
|
flat.push(message);
|
||||||
});
|
|
||||||
return flat;
|
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
return flat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getSettingMessages(){
|
async function getSettingMessages(){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const settingStrings = require("../lib/settingStrings");
|
const settingStrings = require("../lib/settingStrings");
|
||||||
const settingDefinitions = require("../lib/settingDefinitions");
|
const settingDefinitions = require("../lib/settingDefinitions");
|
||||||
function getDefinition(name){
|
function getDefinition(name){
|
||||||
@ -113,33 +114,53 @@ async function getSettingMessages(){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const presets = require("../options/presets.json");
|
||||||
|
Object.keys(presets).forEach(function(preset){
|
||||||
|
foundMessages.push("preset_" + preset + "_title");
|
||||||
|
foundMessages.push("preset_" + preset + "_description");
|
||||||
|
});
|
||||||
return foundMessages.map(function(message){return message.toLowerCase();});
|
return foundMessages.map(function(message){return message.toLowerCase();});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getKnownMessages(){
|
async function getKnownMessages(){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"addon_title",
|
"addon_title",
|
||||||
"addon_description",
|
"addon_description",
|
||||||
"urlsettings_title",
|
"urlSettings_title",
|
||||||
"installnotice",
|
"installnotice",
|
||||||
|
"presets_installnotice",
|
||||||
"updatenotice",
|
"updatenotice",
|
||||||
"disablenotifications",
|
"disableNotifications",
|
||||||
"showoptions",
|
"showoptions",
|
||||||
"displayhiddensettings_title",
|
"displayHiddenSettings_title",
|
||||||
"displayhiddensettings_description",
|
"displayHiddenSettings_description",
|
||||||
"browseraction_settings",
|
"browseraction_settings",
|
||||||
"browseraction_test",
|
"browseraction_test",
|
||||||
"browseraction_review",
|
"browseraction_review",
|
||||||
"browseraction_reportissue",
|
"browseraction_reportIssue",
|
||||||
];
|
].map(function(message){
|
||||||
|
return message.toLowerCase();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const en = require("../_locales/en/messages.json");
|
async function main(){
|
||||||
const declaredMessages = Object.keys(en)
|
"use strict";
|
||||||
// .filter(function(key){return en[key].message;})
|
const en = require("../_locales/en/messages.json");
|
||||||
.map(function(key){return key.toLowerCase();});
|
const declaredMessages = Object.keys(en)
|
||||||
Promise.all([getSettingMessages(), getMessagesInFolder(path.join(__dirname, "..")), getKnownMessages()]).then(function([settingMessages, fileMessages, knownMessages]){
|
// .filter(function(key){return en[key].message;})
|
||||||
|
.map(function(key){
|
||||||
|
return key.toLowerCase();
|
||||||
|
});
|
||||||
|
const [settingMessages, fileMessages, knownMessages] = await Promise.all([
|
||||||
|
getSettingMessages(),
|
||||||
|
getMessagesInFolder(path.join(__dirname, "..")),
|
||||||
|
getKnownMessages()]
|
||||||
|
);
|
||||||
|
|
||||||
declaredMessages.forEach(function(message){
|
declaredMessages.forEach(function(message){
|
||||||
|
|
||||||
if (
|
if (
|
||||||
fileMessages.indexOf(message) === -1 &&
|
fileMessages.indexOf(message) === -1 &&
|
||||||
settingMessages.indexOf(message) === -1 &&
|
settingMessages.indexOf(message) === -1 &&
|
||||||
@ -148,4 +169,6 @@ Promise.all([getSettingMessages(), getMessagesInFolder(path.join(__dirname, ".."
|
|||||||
console.log(`usage of ${message} not found`);
|
console.log(`usage of ${message} not found`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
main();
|
@ -8,35 +8,39 @@ const language = process.argv[2];
|
|||||||
|
|
||||||
|
|
||||||
function getTranslationPath(language){
|
function getTranslationPath(language){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
return path.join(__dirname, "../_locales/" + language + "/messages.json");
|
return path.join(__dirname, "../_locales/" + language + "/messages.json");
|
||||||
}
|
}
|
||||||
async function loadTranslation(language){
|
async function loadTranslation(language){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const path = getTranslationPath(language);
|
const path = getTranslationPath(language);
|
||||||
return await util.promisify(fs.exists)(path)
|
const exists = await util.promisify(fs.exists)(path);
|
||||||
.then(function(exists){
|
if (exists){
|
||||||
if (exists){
|
console.log("language exists -> load data");
|
||||||
console.log("language exists -> load data");
|
const data = await util.promisify(fs.readFile)(path, {encoding: "UTF-8"});
|
||||||
return util.promisify(fs.readFile)(path, {encoding: "UTF-8"})
|
return JSON.parse(data);
|
||||||
.then(function(data){
|
}
|
||||||
return JSON.parse(data);
|
else {
|
||||||
});
|
console.log("language does not exist -> create it");
|
||||||
}
|
return {};
|
||||||
else {
|
}
|
||||||
console.log("language does not exist -> create it");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveTranslation(language, data){
|
async function saveTranslation(language, data){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const path = getTranslationPath(language);
|
const path = getTranslationPath(language);
|
||||||
return await util.promisify(fs.writeFile)(path, JSON.stringify(data, null, "\t"));
|
return await util.promisify(fs.writeFile)(path, JSON.stringify(data, null, "\t"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getInput(prompt){
|
async function getInput(prompt){
|
||||||
return new Promise(function(resolve, reject){
|
"use strict";
|
||||||
|
|
||||||
|
return new Promise(function(resolve){
|
||||||
process.stdout.write(prompt);
|
process.stdout.write(prompt);
|
||||||
process.stdin.setEncoding('utf8');
|
process.stdin.setEncoding("utf8");
|
||||||
process.stdin.resume();
|
process.stdin.resume();
|
||||||
process.stdin.on("data", function onData(data){
|
process.stdin.on("data", function onData(data){
|
||||||
process.stdin.removeListener("data", onData);
|
process.stdin.removeListener("data", onData);
|
||||||
@ -47,18 +51,22 @@ async function getInput(prompt){
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function askForTranslation(key){
|
async function askForTranslation(key){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const enData = en[key];
|
const enData = en[key];
|
||||||
console.log("English translation for", key, ":", enData.message);
|
console.log("English translation for", key, ":", enData.message);
|
||||||
if (enData.description){
|
if (enData.description){
|
||||||
console.log("\nDescription:", enData.description);
|
console.log("\nDescription:", enData.description);
|
||||||
}
|
}
|
||||||
return await getInput("Please enter translation: ");
|
return getInput("Please enter translation: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function translate(language){
|
async function translate(language){
|
||||||
|
"use strict";
|
||||||
|
|
||||||
const originalData = await loadTranslation(language);
|
const originalData = await loadTranslation(language);
|
||||||
const data = {};
|
const data = {};
|
||||||
for (var i = 0; i < enKeys.length; i += 1){
|
for (let i = 0; i < enKeys.length; i += 1){
|
||||||
const key = enKeys[i];
|
const key = enKeys[i];
|
||||||
const oldData = originalData[key];
|
const oldData = originalData[key];
|
||||||
const enData = en[key];
|
const enData = en[key];
|
||||||
@ -75,6 +83,10 @@ async function translate(language){
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
translate(language).then(function(data){
|
(async function(){
|
||||||
return saveTranslation(language, data);
|
"use strict";
|
||||||
});
|
|
||||||
|
const data = await translate(language);
|
||||||
|
|
||||||
|
saveTranslation(language, data);
|
||||||
|
}());
|
73
.vscode/settings.json
vendored
@ -1,51 +1,84 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
|
"arial",
|
||||||
"Benachrichtigungsdetails",
|
"Benachrichtigungsdetails",
|
||||||
|
"benachrichtigungsicon",
|
||||||
"Blockiermodi",
|
"Blockiermodi",
|
||||||
"Blockiermodus",
|
"Blockiermodus",
|
||||||
|
"canvasblocker",
|
||||||
"Captcha",
|
"Captcha",
|
||||||
|
"checkmark",
|
||||||
|
"collapser",
|
||||||
|
"Coord",
|
||||||
|
"darkgreen",
|
||||||
|
"dont",
|
||||||
|
"fakeable",
|
||||||
|
"Fenix",
|
||||||
|
"fragmenter",
|
||||||
"Funktionalitätstest",
|
"Funktionalitätstest",
|
||||||
|
"Funktionalitätstests",
|
||||||
|
"graytext",
|
||||||
|
"Hyrp",
|
||||||
|
"iframe",
|
||||||
|
"ignorelist",
|
||||||
"Ignorierliste",
|
"Ignorierliste",
|
||||||
"KHTML",
|
"KHTML",
|
||||||
"Krasnaya",
|
"Krasnaya",
|
||||||
|
"lightgray",
|
||||||
"Maleficient",
|
"Maleficient",
|
||||||
|
"mediump",
|
||||||
|
"micrococo",
|
||||||
|
"monero",
|
||||||
|
"monospace",
|
||||||
"Nachfrageverweigerungsmodus",
|
"Nachfrageverweigerungsmodus",
|
||||||
|
"nocanvas",
|
||||||
"Oakenpants",
|
"Oakenpants",
|
||||||
"PDFs",
|
"onedrive",
|
||||||
|
"onloaded",
|
||||||
|
"oscpu",
|
||||||
"Palemoon",
|
"Palemoon",
|
||||||
|
"paypal",
|
||||||
|
"PDFs",
|
||||||
"Ploshchad",
|
"Ploshchad",
|
||||||
|
"prefs",
|
||||||
|
"promisify",
|
||||||
|
"recaptcha",
|
||||||
"Rect",
|
"Rect",
|
||||||
"Rects",
|
"Rects",
|
||||||
|
"ruleset",
|
||||||
|
"spodermenpls",
|
||||||
"Spoofer",
|
"Spoofer",
|
||||||
|
"statechange",
|
||||||
"Strg",
|
"Strg",
|
||||||
|
"SVGAPI",
|
||||||
"Thorin",
|
"Thorin",
|
||||||
|
"Tiie",
|
||||||
|
"unticking",
|
||||||
"Vortäuschaktion",
|
"Vortäuschaktion",
|
||||||
"Vortäuschgröße",
|
"Vortäuschgröße",
|
||||||
"Vortäuschrate",
|
"Vortäuschrate",
|
||||||
"Waterfox",
|
"Waterfox",
|
||||||
"benachrichtigungsicon",
|
|
||||||
"collapser",
|
|
||||||
"dont",
|
|
||||||
"fakeable",
|
|
||||||
"fragmenter",
|
|
||||||
"graytext",
|
|
||||||
"iframe",
|
|
||||||
"ignorelist",
|
|
||||||
"micrococo",
|
|
||||||
"monero",
|
|
||||||
"onedrive",
|
|
||||||
"onloaded",
|
|
||||||
"oscpu",
|
|
||||||
"prefs",
|
|
||||||
"promisify",
|
|
||||||
"ruleset",
|
|
||||||
"spodermenpls",
|
|
||||||
"unticking",
|
|
||||||
"webgl",
|
"webgl",
|
||||||
"whitelisted",
|
"whitelisted",
|
||||||
"writeln",
|
"writeln",
|
||||||
"wyciwyg",
|
"wyciwyg",
|
||||||
"yfdyh"
|
"yfdyh"
|
||||||
],
|
],
|
||||||
"cSpell.language": "en,de,en-GB"
|
"cSpell.language": "en,de,en-GB",
|
||||||
|
"cSpell.ignorePaths": [
|
||||||
|
"**/package-lock.json",
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/vscode-extension/**",
|
||||||
|
"**/.git/objects/**",
|
||||||
|
".vscode",
|
||||||
|
".eslintrc.json",
|
||||||
|
".tools/chromeVendors.json"
|
||||||
|
],
|
||||||
|
"eslint.validate": [
|
||||||
|
"javascript",
|
||||||
|
"php",
|
||||||
|
"html"
|
||||||
|
],
|
||||||
|
"eslint.lintTask.enable": true,
|
||||||
|
"cSpell.enabled": true
|
||||||
}
|
}
|
43
.vscode/tasks.json
vendored
@ -16,7 +16,9 @@
|
|||||||
"command": "eslint"
|
"command": "eslint"
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
"./"
|
"./",
|
||||||
|
"--ext",
|
||||||
|
".js,.html,.php"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
@ -43,7 +45,7 @@
|
|||||||
"-f",
|
"-f",
|
||||||
"nightly",
|
"nightly",
|
||||||
"--url",
|
"--url",
|
||||||
"http://canvasblocker.local/test/"
|
"http://canvasblocker.localhost/test/"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
@ -68,7 +70,7 @@
|
|||||||
"args": [
|
"args": [
|
||||||
"run",
|
"run",
|
||||||
"--url",
|
"--url",
|
||||||
"http://canvasblocker.local/test/"
|
"http://canvasblocker.localhost/test/"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
@ -95,7 +97,7 @@
|
|||||||
"-f",
|
"-f",
|
||||||
"firefox-esr",
|
"firefox-esr",
|
||||||
"--url",
|
"--url",
|
||||||
"http://canvasblocker.local/test/"
|
"http://canvasblocker.localhost/test/"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
@ -122,7 +124,7 @@
|
|||||||
"-f",
|
"-f",
|
||||||
"firefox-beta",
|
"firefox-beta",
|
||||||
"--url",
|
"--url",
|
||||||
"http://canvasblocker.local/test/"
|
"http://canvasblocker.localhost/test/"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
@ -150,7 +152,36 @@
|
|||||||
"--ignore-files",
|
"--ignore-files",
|
||||||
"test",
|
"test",
|
||||||
"--ignore-files",
|
"--ignore-files",
|
||||||
"versions"
|
"versions",
|
||||||
|
"--ignore-files",
|
||||||
|
"crowdin.yml",
|
||||||
|
"--ignore-files",
|
||||||
|
"package*"
|
||||||
|
],
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build alpha",
|
||||||
|
"type": "shell",
|
||||||
|
"windows": {
|
||||||
|
"command": "node"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"command": "node"
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"command": "node"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
".tools/build.js",
|
||||||
|
"--type",
|
||||||
|
"alpha"
|
||||||
],
|
],
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"echo": true,
|
"echo": true,
|
||||||
|
42
README.md
@ -1,10 +1,27 @@
|
|||||||
|
CanvasBlocker [![codebeat badge](https://codebeat.co/badges/0edd6c9f-250a-4f1e-9c64-0958741522af)](https://codebeat.co/projects/github-com-kkapsner-canvasblocker-master)
|
||||||
|
=====
|
||||||
|
|
||||||
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.
|
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)
|
**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.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
Protected "fingerprinting" APIs:
|
||||||
|
* canvas 2d
|
||||||
|
* webGL
|
||||||
|
* audio
|
||||||
|
* history
|
||||||
|
* window (disabled by default)
|
||||||
|
* DOMRect
|
||||||
|
* SVG
|
||||||
|
* TextMetrics
|
||||||
|
* navigator (disabled by default)
|
||||||
|
* screen
|
||||||
|
|
||||||
More information on fingerprinting can be found at:
|
More information on fingerprinting can be found at:
|
||||||
* <canvas>: http://www.browserleaks.com/canvas
|
* <canvas>: https://www.browserleaks.com/canvas
|
||||||
* audio:
|
* audio:
|
||||||
* https://audiofingerprint.openwpm.com/ (very poorly written = slow)
|
* https://audiofingerprint.openwpm.com/ (very poorly written = slow)
|
||||||
* https://webtransparency.cs.princeton.edu/webcensus/#audio-fp
|
* https://webtransparency.cs.princeton.edu/webcensus/#audio-fp
|
||||||
@ -13,6 +30,12 @@ More information on fingerprinting can be found at:
|
|||||||
* https://browserleaks.com/rects
|
* https://browserleaks.com/rects
|
||||||
* https://github.com/ghacksuserjs/ghacks-user.js/wiki/Appendix-A---Test-Sites
|
* https://github.com/ghacksuserjs/ghacks-user.js/wiki/Appendix-A---Test-Sites
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
Beta versions can be found at https://canvasblocker.kkapsner.de/versions/.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
The different block modes are:
|
The different block modes are:
|
||||||
* fake: Canvas Blocker's default setting, and my favorite! All websites not on the white list or black list can use the protected APIs. But values obtained by the APIs are altered so that a consistent fingerprinting is not possible
|
* fake: Canvas Blocker's default setting, and my favorite! All websites not on the white list or black list can use the protected APIs. But values obtained by the APIs are altered so that a consistent fingerprinting is not possible
|
||||||
* ask for permission: If a website is not listed on the white list or black list, the user will be asked if the website should be allowed to use the protected APIs each time they are called.
|
* ask for permission: If a website is not listed on the white list or black list, the user will be asked if the website should be allowed to use the protected APIs each time they are called.
|
||||||
@ -21,14 +44,9 @@ The different block modes are:
|
|||||||
* block only black list: Block the protected APIs only for websites on the black list.
|
* block only black list: Block the protected APIs only for websites on the black list.
|
||||||
* allow everything: Ignore all lists and allow the protected APIs on all websites.
|
* allow everything: Ignore all lists and allow the protected APIs on all websites.
|
||||||
|
|
||||||
Protected "fingerprinting" APIs:
|
-----
|
||||||
* canvas 2d
|
|
||||||
* webGL
|
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.
|
||||||
* audio
|
|
||||||
* history
|
|
||||||
* window (disabled by default)
|
|
||||||
* DOMRect
|
|
||||||
* navigator (disabled by default)
|
|
||||||
|
|
||||||
Special thanks to:
|
Special thanks to:
|
||||||
* spodermenpls for finding all the typos
|
* spodermenpls for finding all the typos
|
||||||
@ -39,9 +57,9 @@ Special thanks to:
|
|||||||
* micrococo for the Spanish translation
|
* micrococo for the Spanish translation
|
||||||
* STim99 for the Russian translation
|
* STim99 for the Russian translation
|
||||||
|
|
||||||
Beta versions can be found at https://canvasblocker.kkapsner.de/versions/.
|
-----
|
||||||
|
|
||||||
If you want to support this addon you can donate to the following addresses:
|
If you want to support this addon you can donate to the following addresses:
|
||||||
* bitcoin: 159Y9BLcfHyrp6wj6f3syEuk92xkRVTiie
|
* bitcoin: 159Y9BLcfHyrp6wj6f3syEuk92xkRVTiie
|
||||||
* bitcoin cash:qrchnszkdwv9knhg9wjucrqy43rpl4klkq7jhkc8dz
|
* bitcoin cash:qrchnszkdwv9knhg9wjucrqy43rpl4klkq7jhkc8dz
|
||||||
* monero: 482QYZaagALWtPmwbptwBaexDYmcVsJrhJp2VVjTgjYA3Kk1YyMdSg9Wz2qz1Gh31E843PFVCDWS4hR4Bjf6ipWuB9iz2cs
|
* monero: 482QYZaagALWtPmwbptwBaexDYmcVsJrhJp2VVjTgjYA3Kk1YyMdSg9Wz2qz1Gh31E843PFVCDWS4hR4Bjf6ipWuB9iz2cs
|
||||||
|
1670
_locales/cs/messages.json
Normal file
@ -4,7 +4,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"addon_description": {
|
"addon_description": {
|
||||||
"message": "Verändert einige JS-APIs um Fingerprinting zu verhindern.",
|
"message": "Verändert einige JS-APIs, um Fingerprinting zu verhindern.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"browserAction_title_default": {
|
"browserAction_title_default": {
|
||||||
@ -20,7 +20,15 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"browserAction_title_protectedAPIs": {
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"more": {
|
"more": {
|
||||||
@ -64,7 +72,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"options_title": {
|
"options_title": {
|
||||||
"message": "CanvasBlocker Einstellungen",
|
"message": "CanvasBlocker-Einstellungen",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"optionsIntroduction": {
|
"optionsIntroduction": {
|
||||||
@ -83,10 +91,22 @@
|
|||||||
"message": "Bei Aktualisierung nicht wieder anzeigen.",
|
"message": "Bei Aktualisierung nicht wieder anzeigen.",
|
||||||
"description": ""
|
"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": {
|
"openInTab": {
|
||||||
"message": "In separatem Tab öffnen",
|
"message": "In separatem Tab öffnen",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"labelForDefaultOption": {
|
||||||
|
"message": " (Standard)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"group_general": {
|
"group_general": {
|
||||||
"message": "Allgemein",
|
"message": "Allgemein",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -96,7 +116,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"group_misc": {
|
"group_misc": {
|
||||||
"message": "Vermischtes",
|
"message": "Sonstiges",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_asking": {
|
"section_asking": {
|
||||||
@ -116,7 +136,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_misc": {
|
"section_misc": {
|
||||||
"message": "Vermischtes",
|
"message": "Sonstiges",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_settings": {
|
"section_settings": {
|
||||||
@ -143,10 +163,22 @@
|
|||||||
"message": "DOMRect-API",
|
"message": "DOMRect-API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"section_SVG-api": {
|
||||||
|
"message": "SVG-API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"section_TextMetrics-api": {
|
||||||
|
"message": "TextMetrics-API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"section_Navigator-api": {
|
"section_Navigator-api": {
|
||||||
"message": "Navigator-API",
|
"message": "Navigator-API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"section_Screen-api": {
|
||||||
|
"message": "Screen-API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"displayAdvancedSettings_title": {
|
"displayAdvancedSettings_title": {
|
||||||
"message": "Expertenmodus",
|
"message": "Expertenmodus",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -163,6 +195,26 @@
|
|||||||
"message": "Zeigt die Beschreibungen der Einstellungen an.",
|
"message": "Zeigt die Beschreibungen der Einstellungen an.",
|
||||||
"description": ""
|
"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": {
|
"hideSetting": {
|
||||||
"message": "Hier klicken, um diese Einstellung zu verbergen.",
|
"message": "Hier klicken, um diese Einstellung zu verbergen.",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -259,6 +311,30 @@
|
|||||||
"message": "Wollen Sie das Auslesen über die DOMRect-API erlauben?",
|
"message": "Wollen Sie das Auslesen über die DOMRect-API erlauben?",
|
||||||
"description": ""
|
"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": {
|
"askForNavigatorPermission": {
|
||||||
"message": "Wollen Sie die Navigator-API erlauben?",
|
"message": "Wollen Sie die Navigator-API erlauben?",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -271,6 +347,18 @@
|
|||||||
"message": "Wollen Sie das Auslesen über die Navigator-API erlauben?",
|
"message": "Wollen Sie das Auslesen über die Navigator-API erlauben?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"askForScreenPermission": {
|
||||||
|
"message": "Wollen Sie die Screen-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForScreenInputPermission": {
|
||||||
|
"message": "Wollen Sie das Schreiben über die Screen-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForScreenReadoutPermission": {
|
||||||
|
"message": "Wollen Sie das Auslesen über die Screen-API erlauben?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"askOnlyOnce_title": {
|
"askOnlyOnce_title": {
|
||||||
"message": "Nur einmal nachfragen",
|
"message": "Nur einmal nachfragen",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -420,7 +508,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.persistent": {
|
"rng_options.persistent": {
|
||||||
@ -432,7 +520,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.nonPersistent": {
|
"rng_options.nonPersistent": {
|
||||||
"message": "nicht persistent",
|
"message": "nichtpersistent",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.white": {
|
"rng_options.white": {
|
||||||
@ -551,6 +639,38 @@
|
|||||||
"message": "Aktiviert das Vortäuschen des Alpha-Kanals (Transparenz).",
|
"message": "Aktiviert das Vortäuschen des Alpha-Kanals (Transparenz).",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"webGLVendor_title": {
|
||||||
|
"message": "Verwendeter webGL \"vendor\"",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLVendor_description": {
|
||||||
|
"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": {
|
||||||
|
"message": "Verwendeter webGL \"renderer\"",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLRenderer_description": {
|
||||||
|
"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": {
|
||||||
|
"message": "Verwendeter webGL \"unmasked vendor\"",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedVendor_description": {
|
||||||
|
"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": {
|
||||||
|
"message": "Verwendeter webGL \"unmasked renderer\"",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedRenderer_description": {
|
||||||
|
"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": {
|
"useCanvasCache_title": {
|
||||||
"message": "Zwischenspeicher für Canvas verwenden",
|
"message": "Zwischenspeicher für Canvas verwenden",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -619,10 +739,22 @@
|
|||||||
"message": "DOMRect-Auslese vorgetäuscht auf {url}",
|
"message": "DOMRect-Auslese vorgetäuscht auf {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedSVGReadout": {
|
||||||
|
"message": "SVG-Auslese vorgetäuscht auf {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakedTextMetricsReadout": {
|
||||||
|
"message": "TextMetrics-Auslese vorgetäuscht auf {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedNavigatorReadout": {
|
"fakedNavigatorReadout": {
|
||||||
"message": "Navigator-Auslese vorgetäuscht auf {url}",
|
"message": "Navigator-Auslese vorgetäuscht auf {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedScreenReadout": {
|
||||||
|
"message": "Screen-Auslese vorgetäuscht auf {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedInput": {
|
"fakedInput": {
|
||||||
"message": "Bei Ausgabe vorgetäuscht auf {url}",
|
"message": "Bei Ausgabe vorgetäuscht auf {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -707,6 +839,10 @@
|
|||||||
"message": "Was soll erlaubt werden?",
|
"message": "Was soll erlaubt werden?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"selectWhitelistType": {
|
||||||
|
"message": "Wie soll erlaubt werden?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"whitelistOnlyAPI": {
|
"whitelistOnlyAPI": {
|
||||||
"message": "Erlaube nur die {api}",
|
"message": "Erlaube nur die {api}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1016,7 +1152,19 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"protectWindow_askReCaptchaException": {
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"protectDOMRect_title": {
|
"protectDOMRect_title": {
|
||||||
@ -1039,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.",
|
"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": ""
|
"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": {
|
"protectNavigator_title": {
|
||||||
"message": "Navigator-API beschützen",
|
"message": "Navigator-API beschützen",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1075,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.",
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"navigatorSettings_contextualIdentities": {
|
||||||
|
"message": "Es werden die Einstellungen der Tab-Umgebung {select} gezeigt.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"navigatorSettings_presetSection.os": {
|
"navigatorSettings_presetSection.os": {
|
||||||
"message": "Betriebssystemvoreinstellungen",
|
"message": "Betriebssystemvoreinstellungen",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1091,6 +1267,42 @@
|
|||||||
"message": "Zurücksetzen",
|
"message": "Zurücksetzen",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"protectScreen_title": {
|
||||||
|
"message": "Screen-API beschützen",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectScreen_description": {
|
||||||
|
"message": "Dies schützt vor Fingerprinting, das die Bildschirmgröße einbezieht.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectScreen_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": ""
|
||||||
|
},
|
||||||
|
"screenSize_title": {
|
||||||
|
"message": "Bildschirmgröße",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"screenSize_description": {
|
||||||
|
"message": "Wenn dies auf einen Wert \"...x...\" gesetzt wird, werden diese Größen als Bildschirmgröße verwendet.",
|
||||||
|
"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ünschte Domain oder URL mit einem Klick auf \"+\" hinzu und geben sie den gewünschten Wert ein.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_title": {
|
||||||
|
"message": "Minimale Bildschirmgröße vortäuschen",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_description": {
|
||||||
|
"message": "Verwende die minimale Bildschirmgröße aus der folgenden Liste, die zur inneren Browserfenstergröße passt. Bildschirmgrößen: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_urlSpecific": {
|
||||||
|
"message": "Um bestimmte Seiten von dem Vortäuschen 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": ""
|
||||||
|
},
|
||||||
"theme_title": {
|
"theme_title": {
|
||||||
"message": "Theme",
|
"message": "Theme",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1247,6 +1459,10 @@
|
|||||||
"message": "Einstellungen",
|
"message": "Einstellungen",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"browserAction_faq": {
|
||||||
|
"message": "FAQ",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"browserAction_test": {
|
"browserAction_test": {
|
||||||
"message": "Testen",
|
"message": "Testen",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1307,6 +1523,10 @@
|
|||||||
"message": "Alle Funktionen der {api} sind deaktiviert, aber der Schutz ist eingeschaltet.",
|
"message": "Alle Funktionen der {api} sind deaktiviert, aber der Schutz ist eingeschaltet.",
|
||||||
"description": ""
|
"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": {
|
"sanitation_resolution.disableMainFlag": {
|
||||||
"message": "Hauptschalter deaktivieren",
|
"message": "Hauptschalter deaktivieren",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1340,7 +1560,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"sanitation_resolution.switchToNonPersistentRng": {
|
"sanitation_resolution.switchToNonPersistentRng": {
|
||||||
"message": "wechsle zu \"nicht persistent\"",
|
"message": "wechsle zu \"nichtpersistent\"",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"sanitation_error.fakeEverythingInCanvas": {
|
"sanitation_error.fakeEverythingInCanvas": {
|
||||||
@ -1375,10 +1595,18 @@
|
|||||||
"message": "Teilen Sie die persistenten Zufallszahlen nicht zwischen Domains, da dies den Browser 100% eindeutig identifizierbar macht.",
|
"message": "Teilen Sie die persistenten Zufallszahlen nicht zwischen Domains, da dies den Browser 100% eindeutig identifizierbar macht.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"sanitation_error.customScreenSize": {
|
||||||
|
"message": "Verwenden Sie keine benutzerdefinierte Bildschirmgröße, da sie den Browser verfolgbarer macht.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"whitelist_inspection_title": {
|
"whitelist_inspection_title": {
|
||||||
"message": "CanvasBlocker Erlaubnisse ansehen",
|
"message": "CanvasBlocker Erlaubnisse ansehen",
|
||||||
"description": ""
|
"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": {
|
"whitelist_all_apis": {
|
||||||
"message": "Alle APIs",
|
"message": "Alle APIs",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1428,7 +1656,15 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"preset_max_protection_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": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,14 @@
|
|||||||
"message": "\n \u00B7 {api}",
|
"message": "\n \u00B7 {api}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"browserAction_status_on": {
|
||||||
|
"message": "CanvasBlocker on",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"browserAction_status_off": {
|
||||||
|
"message": "CanvasBlocker off",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"more": {
|
"more": {
|
||||||
"message": "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.",
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"dontShowOptionsOnUpdate":{
|
"dontShowOptionsOnUpdate": {
|
||||||
"message": "Don't show up again after update.",
|
"message": "Don't show up again after update.",
|
||||||
"description": ""
|
"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": {
|
"openInTab": {
|
||||||
"message": "Open in separate tab",
|
"message": "Open in separate tab",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"labelForDefaultOption": {
|
||||||
|
"message": " (default)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"group_general": {
|
"group_general": {
|
||||||
"message": "General",
|
"message": "General",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -130,30 +151,42 @@
|
|||||||
"message": "Settings",
|
"message": "Settings",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_canvas-api":{
|
"section_canvas-api": {
|
||||||
"message": "Canvas API",
|
"message": "Canvas API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_audio-api":{
|
"section_audio-api": {
|
||||||
"message": "Audio API",
|
"message": "Audio API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_history-api":{
|
"section_history-api": {
|
||||||
"message": "History API",
|
"message": "History API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_window-api":{
|
"section_window-api": {
|
||||||
"message": "Window API",
|
"message": "Window API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_DOMRect-api":{
|
"section_DOMRect-api": {
|
||||||
"message": "DOMRect API",
|
"message": "DOMRect API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"section_Navigator-api":{
|
"section_SVG-api": {
|
||||||
|
"message": "SVG API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"section_TextMetrics-api": {
|
||||||
|
"message": "TextMetrics API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"section_Navigator-api": {
|
||||||
"message": "Navigator API",
|
"message": "Navigator API",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"section_Screen-api": {
|
||||||
|
"message": "Screen API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"displayAdvancedSettings_title": {
|
"displayAdvancedSettings_title": {
|
||||||
"message": "Expert mode",
|
"message": "Expert mode",
|
||||||
@ -173,6 +206,28 @@
|
|||||||
"description": ""
|
"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": {
|
"hideSetting": {
|
||||||
"message": "Click here to hide this setting.",
|
"message": "Click here to hide this setting.",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -271,6 +326,30 @@
|
|||||||
"message": "Do you want to allow DOMRect API readout?",
|
"message": "Do you want to allow DOMRect API readout?",
|
||||||
"description": ""
|
"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": {
|
"askForNavigatorPermission": {
|
||||||
"message": "Do you want to allow the navigator API?",
|
"message": "Do you want to allow the navigator API?",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -283,12 +362,24 @@
|
|||||||
"message": "Do you want to allow navigator API readout?",
|
"message": "Do you want to allow navigator API readout?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"askForScreenPermission": {
|
||||||
|
"message": "Do you want to allow the screen API?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForScreenInputPermission": {
|
||||||
|
"message": "Do you want to allow screen API input?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"askForScreenReadoutPermission": {
|
||||||
|
"message": "Do you want to allow screen API readout?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"askOnlyOnce_title": {
|
"askOnlyOnce_title": {
|
||||||
"message": "Ask only once",
|
"message": "Ask only once",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askOnlyOnce_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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askOnlyOnce_options.no": {
|
"askOnlyOnce_options.no": {
|
||||||
@ -303,32 +394,32 @@
|
|||||||
"message": "combined",
|
"message": "combined",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askDenyMode_title":{
|
"askDenyMode_title": {
|
||||||
"message": "Ask deny mode",
|
"message": "Ask deny mode",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askDenyMode_description":{
|
"askDenyMode_description": {
|
||||||
"message": "Which mode shall be used when the permission is denied.",
|
"message": "Which mode shall be used when the permission is denied.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askDenyMode_options.block":{
|
"askDenyMode_options.block": {
|
||||||
"message": "block",
|
"message": "block",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"askDenyMode_options.fake":{
|
"askDenyMode_options.fake": {
|
||||||
"message": "fake",
|
"message": "fake",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
"showCanvasWhileAsking_title":{
|
"showCanvasWhileAsking_title": {
|
||||||
"message": "Show canvas content",
|
"message": "Show canvas content",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"showCanvasWhileAsking_description":{
|
"showCanvasWhileAsking_description": {
|
||||||
"message": "Shows the content of the canvas for which the permission is asked for, if possible.",
|
"message": "Shows the content of the canvas for which the permission is asked for, if possible.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"showCanvasWhileAsking_message":{
|
"showCanvasWhileAsking_message": {
|
||||||
"message": "The webpage wants to read the content of the following canvas:",
|
"message": "The webpage wants to read the content of the following canvas:",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
@ -409,7 +500,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"urlSettings_title": {
|
"urlSettings_title": {
|
||||||
"message": "Site specific values",
|
"message": "Site-specific values",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"urlSettings_description": {
|
"urlSettings_description": {
|
||||||
@ -441,7 +532,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"rng_description": {
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.persistent": {
|
"rng_options.persistent": {
|
||||||
@ -453,7 +544,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.nonPersistent": {
|
"rng_options.nonPersistent": {
|
||||||
"message": "non persistent",
|
"message": "nonpersistent",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"rng_options.white": {
|
"rng_options.white": {
|
||||||
@ -581,6 +672,39 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"webGLVendor_title": {
|
||||||
|
"message": "Reported webGL vendor",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLVendor_description": {
|
||||||
|
"message": "Value to be reported in the webGL function \"getParameter\" for the \"vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLRenderer_title": {
|
||||||
|
"message": "Reported webGL renderer",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLRenderer_description": {
|
||||||
|
"message": "Value to be reported in the webGL function \"getParameter\" for the \"renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedVendor_title": {
|
||||||
|
"message": "Reported webGL unmasked vendor",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedVendor_description": {
|
||||||
|
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked vendor\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedRenderer_title": {
|
||||||
|
"message": "Reported webGL unmasked renderer",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"webGLUnmaskedRenderer_description": {
|
||||||
|
"message": "Value to be reported in the webGL function \"getParameter\" for the \"unmasked renderer\". Special values:\nLeave empty to use the original value\n\n{undefined}: returns undefined (#508)\n\n{false}: returns the boolean value false (#508)\n\n{empty}: returns an empty string (#508)\n\n{disabled}: returns null (#508)\n\n{random vendor}: returns a random vendor from the built-in list (#493)\n\n{random renderer}: returns a random renderer from the built-in list (#493)\n\n<xxx|yyy|zzz>: picks one of the given options xxx, yyy or zzz at random (arbitrary number of options) (#493)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"useCanvasCache_title": {
|
"useCanvasCache_title": {
|
||||||
"message": "Use canvas cache",
|
"message": "Use canvas cache",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -652,10 +776,22 @@
|
|||||||
"message": "Faked DOMRect readout on {url}",
|
"message": "Faked DOMRect readout on {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedSVGReadout": {
|
||||||
|
"message": "Faked SVG readout on {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakedTextMetricsReadout": {
|
||||||
|
"message": "Faked TextMetrics readout on {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedNavigatorReadout": {
|
"fakedNavigatorReadout": {
|
||||||
"message": "Faked navigator readout on {url}",
|
"message": "Faked navigator readout on {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"fakedScreenReadout": {
|
||||||
|
"message": "Faked screen readout on {url}",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"fakedInput": {
|
"fakedInput": {
|
||||||
"message": "Faked at input on {url}",
|
"message": "Faked at input on {url}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -742,6 +878,10 @@
|
|||||||
"message": "What is the scope of the whitelisting?",
|
"message": "What is the scope of the whitelisting?",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"selectWhitelistType": {
|
||||||
|
"message": "What is the type of the whitelisting?",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"whitelistOnlyAPI": {
|
"whitelistOnlyAPI": {
|
||||||
"message": "Whitelist only the {api}",
|
"message": "Whitelist only the {api}",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1058,7 +1198,20 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"protectWindow_askReCaptchaException": {
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1084,6 +1237,32 @@
|
|||||||
"description": ""
|
"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": {
|
"protectNavigator_title": {
|
||||||
"message": "Protect navigator API",
|
"message": "Protect navigator API",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1122,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.",
|
"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": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"navigatorSettings_contextualIdentities": {
|
||||||
|
"message": "Settings for the container {select} are shown.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"navigatorSettings_presetSection.os": {
|
"navigatorSettings_presetSection.os": {
|
||||||
"message": "Operating system presets",
|
"message": "Operating system presets",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1139,6 +1322,43 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"protectScreen_title": {
|
||||||
|
"message": "Protect screen API",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectScreen_description": {
|
||||||
|
"message": "This protects against fingerprinting attempts including the screen size.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"protectScreen_urlSpecific": {
|
||||||
|
"message": "To exclude specific websites from this protection, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"screenSize_title": {
|
||||||
|
"message": "Screen size",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"screenSize_description": {
|
||||||
|
"message": "If this is set with a value \"...x...\" the specified dimensions will be reported as the screen size.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"screenSize_urlSpecific": {
|
||||||
|
"message": "To provide specific sizes for certain websites, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and enter the desired value.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_title": {
|
||||||
|
"message": "Fake minimal screen size",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_description": {
|
||||||
|
"message": "Use a minimal screen size from the following set that can fit the inner window dimensions. Screen sizes: 1366x768, 1440x900, 1600x900, 1920x1080, 4096x2160, 8192x4320",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"fakeMinimalScreenSize_urlSpecific": {
|
||||||
|
"message": "To exclude specific websites from the faking, click on the black arrow to open the menu, add the domain or URL by clicking on \"+\" and remove its checkmark.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"theme_title": {
|
"theme_title": {
|
||||||
"message": "Theme",
|
"message": "Theme",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1304,6 +1524,10 @@
|
|||||||
"message": "Settings",
|
"message": "Settings",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"browserAction_faq": {
|
||||||
|
"message": "FAQ",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"browserAction_test": {
|
"browserAction_test": {
|
||||||
"message": "Test",
|
"message": "Test",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1365,6 +1589,10 @@
|
|||||||
"message": "All features of {api} are disabled but the protection is enabled.",
|
"message": "All features of {api} are disabled but the protection is enabled.",
|
||||||
"description": ""
|
"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": {
|
"sanitation_resolution.disableMainFlag": {
|
||||||
"message": "disable main flag",
|
"message": "disable main flag",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1398,7 +1626,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"sanitation_resolution.switchToNonPersistentRng": {
|
"sanitation_resolution.switchToNonPersistentRng": {
|
||||||
"message": "switch to \"non persistent\" rng",
|
"message": "switch to \"nonpersistent\" rng",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"sanitation_error.fakeEverythingInCanvas": {
|
"sanitation_error.fakeEverythingInCanvas": {
|
||||||
@ -1433,11 +1661,19 @@
|
|||||||
"message": "Do not share persistent randomness between domains because this makes the browser 100% trackable.",
|
"message": "Do not share persistent randomness between domains because this makes the browser 100% trackable.",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"sanitation_error.customScreenSize": {
|
||||||
|
"message": "Do not use a custom screen size as it makes the browser more trackable.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"whitelist_inspection_title": {
|
"whitelist_inspection_title": {
|
||||||
"message": "CanvasBlocker whitelist inspection",
|
"message": "CanvasBlocker whitelist inspection",
|
||||||
"description": ""
|
"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": {
|
"whitelist_all_apis": {
|
||||||
"message": "All APIs",
|
"message": "All APIs",
|
||||||
"description": ""
|
"description": ""
|
||||||
@ -1489,7 +1725,15 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"preset_max_protection_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": ""
|
"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 {
|
.action.search {
|
||||||
padding-left: calc(0.5em + 19px + 0.25em);
|
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;
|
||||||
}
|
}
|
@ -4,16 +4,23 @@
|
|||||||
<title>CanvasBlocker browser action</title>
|
<title>CanvasBlocker browser action</title>
|
||||||
<link href="browserAction.css" rel="stylesheet" type="text/css">
|
<link href="browserAction.css" rel="stylesheet" type="text/css">
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="headerActions">
|
||||||
|
<button id="addonStatus" class="undefined"></button>
|
||||||
|
<div id="reload" class="hidden"></div>
|
||||||
|
</div>
|
||||||
<div id="actions" class="stackedInputs"></div>
|
<div id="actions" class="stackedInputs"></div>
|
||||||
<script src="../lib/require.js"></script>
|
<div id="version" class="versionDisplay"></div>
|
||||||
<script src="../lib/extension.js"></script>
|
<script src="../lib/require.js"></script>
|
||||||
<script src="../lib/logging.js"></script>
|
<script src="../lib/logging.js"></script>
|
||||||
<script src="../lib/settingDefinitions.js"></script>
|
<script src="../lib/extension.js"></script>
|
||||||
<script src="../lib/settingContainers.js"></script>
|
<script src="../lib/settingDefinitions.js"></script>
|
||||||
<script src="../lib/settings.js"></script>
|
<script src="../lib/settingContainers.js"></script>
|
||||||
<script src="../lib/theme.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>
|
<script src="browserAction.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -7,72 +7,147 @@
|
|||||||
const extension = require("../lib/extension");
|
const extension = require("../lib/extension");
|
||||||
const logging = require("../lib/logging");
|
const logging = require("../lib/logging");
|
||||||
const settings = require("../lib/settings");
|
const settings = require("../lib/settings");
|
||||||
|
const settingContainers = require("../lib/settingContainers");
|
||||||
|
const lists = require("../lib/lists");
|
||||||
require("../lib/theme").init();
|
require("../lib/theme").init();
|
||||||
logging.message("Opened browser action");
|
logging.message("Opened browser action");
|
||||||
|
|
||||||
settings.onloaded(function(){
|
|
||||||
var 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");
|
||||||
|
}
|
||||||
|
|
||||||
[
|
const currentURL = new URL(currentTab.url);
|
||||||
{
|
const reloadButton = document.getElementById("reload");
|
||||||
label: "settings",
|
reloadButton.addEventListener("click", async function(){
|
||||||
icon: browser.extension.getURL("icons/pageAction-showOptions.svg"),
|
await browser.tabs.reload(currentTab.id, {bypassCache: true});
|
||||||
action: function(){
|
window.close();
|
||||||
if (browser.runtime && browser.runtime.openOptionsPage){
|
});
|
||||||
browser.runtime.openOptionsPage();
|
const addonStatus = document.getElementById("addonStatus");
|
||||||
}
|
addonStatus.addEventListener("click", async function(){
|
||||||
else {
|
reloadButton.classList.toggle("hidden");
|
||||||
window.open(browser.extension.getURL("options/options.html"), "_blank");
|
if (isWhitelisted(currentURL)){
|
||||||
}
|
settingContainers.resetUrlValue("blockMode", currentURL);
|
||||||
|
if (settings.get("blockMode").startsWith("allow")){
|
||||||
|
settings.set("blockMode", "fake", currentURL.host);
|
||||||
}
|
}
|
||||||
},
|
if (settings.get("blockDataURLs")){
|
||||||
{
|
settingContainers.resetUrlValue("blockDataURLs", currentURL);
|
||||||
label: "test",
|
|
||||||
advanced: true,
|
|
||||||
icon: browser.extension.getURL("icons/browserAction-test.svg"),
|
|
||||||
action: function(){
|
|
||||||
window.open("https://canvasblocker.kkapsner.de/test", "_blank");
|
|
||||||
}
|
}
|
||||||
},
|
const entries = lists.get("white").filter(e => e.match(currentURL)).map(e => e.value);
|
||||||
{
|
await Promise.all([
|
||||||
label: "review",
|
lists.removeFrom("white", entries),
|
||||||
icon: browser.extension.getURL("icons/browserAction-review.svg"),
|
lists.removeFrom("sessionWhite", entries)
|
||||||
action: function(){
|
]);
|
||||||
window.open("https://addons.mozilla.org/firefox/addon/canvasblocker/reviews/", "_blank");
|
}
|
||||||
|
else {
|
||||||
|
settings.set("blockMode", "allowEverything", currentURL.hostname);
|
||||||
|
if (settings.get("blockDataURLs")){
|
||||||
|
settings.set("blockDataURLs", false, currentURL.hostname);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
{
|
update();
|
||||||
label: "reportIssue",
|
});
|
||||||
icon: browser.extension.getURL("icons/browserAction-reportIssue.svg"),
|
function update(){
|
||||||
action: function(){
|
if (isWhitelisted(currentURL)){
|
||||||
window.open("https://github.com/kkapsner/CanvasBlocker/issues", "_blank");
|
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();
|
||||||
}
|
}
|
||||||
},
|
else {
|
||||||
].forEach(function(action){
|
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);
|
logging.verbose("Action", action);
|
||||||
if (action.advanced && !settings.displayAdvancedSettings){
|
if (action.advanced && !settings.displayAdvancedSettings){
|
||||||
logging.verbose("Hiding advanced action");
|
logging.verbose("Hiding advanced action");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var actionButton = document.createElement("button");
|
const actionButton = document.createElement("button");
|
||||||
actionButton.className = "action";
|
actionButton.className = "action";
|
||||||
|
|
||||||
var icon = document.createElement("span");
|
const icon = document.createElement("span");
|
||||||
icon.className = "icon";
|
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(icon);
|
||||||
|
|
||||||
actionButton.appendChild(
|
const textNode = document.createTextNode("");
|
||||||
document.createTextNode(
|
function setLabel(label){
|
||||||
extension.getTranslation("browserAction_" + action.label) || action.label
|
textNode.nodeValue = extension.getTranslation("browserAction_" + label) || label;
|
||||||
)
|
}
|
||||||
);
|
setLabel(action.label);
|
||||||
actionButton.addEventListener("click", action.action);
|
|
||||||
|
actionButton.appendChild(textNode);
|
||||||
|
actionButton.addEventListener("click", function(){
|
||||||
|
action.action.call(this, {setIcon, setLabel});
|
||||||
|
});
|
||||||
actions.appendChild(actionButton);
|
actions.appendChild(actionButton);
|
||||||
});
|
});
|
||||||
|
|
||||||
var search = document.createElement("input");
|
const search = document.createElement("input");
|
||||||
search.placeholder = extension.getTranslation("search");
|
search.placeholder = extension.getTranslation("search");
|
||||||
search.className = "search action";
|
search.className = "search action";
|
||||||
actions.appendChild(search);
|
actions.appendChild(search);
|
||||||
@ -80,13 +155,17 @@
|
|||||||
|
|
||||||
search.addEventListener("keypress", function(event){
|
search.addEventListener("keypress", function(event){
|
||||||
if ([10, 13].indexOf(event.keyCode) !== -1){
|
if ([10, 13].indexOf(event.keyCode) !== -1){
|
||||||
window.open(browser.extension.getURL(
|
browser.tabs.create({url: extension.getURL(
|
||||||
"options/options.html" +
|
"options/options.html" +
|
||||||
"?search=" +
|
"?search=" +
|
||||||
encodeURIComponent(this.value)
|
encodeURIComponent(this.value)
|
||||||
));
|
)});
|
||||||
window.close();
|
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"
|
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"
|
id="path2985"
|
||||||
inkscape:connector-curvature="0" />
|
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>
|
</g>
|
||||||
</svg>
|
</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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(0,-1033.3622)">
|
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
|
<path
|
||||||
style="fill:none;stroke:#00be00;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
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"
|
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 |
@ -3,7 +3,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -15,15 +15,15 @@
|
|||||||
|
|
||||||
// Check canvas appearance
|
// Check canvas appearance
|
||||||
function canvasAppearance(window, api, context){
|
function canvasAppearance(window, api, context){
|
||||||
var oldBorder = false;
|
let oldBorder = false;
|
||||||
var canvas = false;
|
let canvas = false;
|
||||||
var inDOM = null;
|
let inDOM = null;
|
||||||
if (api === "canvas" && context){
|
if (api === "canvas" && context){
|
||||||
var nodeName;
|
let nodeName;
|
||||||
try {
|
try {
|
||||||
nodeName = context.nodeName;
|
nodeName = context.nodeName;
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
nodeName = "";
|
nodeName = "";
|
||||||
}
|
}
|
||||||
if (nodeName === "CANVAS"){
|
if (nodeName === "CANVAS"){
|
||||||
@ -45,17 +45,17 @@
|
|||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
askCategory: canvas? (inDOM? "visible": "invisible"): (api === "canvas"? "nocanvas": api),
|
askCategory: canvas? (inDOM? "visible": "invisible"): (api === "canvas"? "nocanvas": api),
|
||||||
get text(){
|
get text(){
|
||||||
var text = canvas? (this.visible? "visible": "invisible"): (api === "canvas"? "nocanvas": api);
|
const text = canvas? (this.visible? "visible": "invisible"): (api === "canvas"? "nocanvas": api);
|
||||||
Object.defineProperty(this, "text", {value: text});
|
Object.defineProperty(this, "text", {value: text});
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
inDom: inDOM,
|
inDom: inDOM,
|
||||||
get visible(){
|
get visible(){
|
||||||
var visible = inDOM;
|
let visible = inDOM;
|
||||||
if (inDOM){
|
if (inDOM){
|
||||||
canvas.scrollIntoView();
|
canvas.scrollIntoView();
|
||||||
var rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
var foundEl = window.document.elementFromPoint(
|
const foundEl = window.document.elementFromPoint(
|
||||||
rect.left + rect.width / 2,
|
rect.left + rect.width / 2,
|
||||||
rect.top + rect.height / 2
|
rect.top + rect.height / 2
|
||||||
);
|
);
|
||||||
@ -72,9 +72,9 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var modes = new WeakMap();
|
const modes = new WeakMap();
|
||||||
function getAskMode(window, type, _){
|
function getAskMode(window, type, _){
|
||||||
var mode = modes.get(window);
|
let mode = modes.get(window);
|
||||||
if (mode){
|
if (mode){
|
||||||
return mode[type];
|
return mode[type];
|
||||||
}
|
}
|
||||||
@ -88,7 +88,8 @@
|
|||||||
audio: _("askForAudioPermission"),
|
audio: _("askForAudioPermission"),
|
||||||
history: _("askForHistoryPermission"),
|
history: _("askForHistoryPermission"),
|
||||||
window: _("askForWindowPermission"),
|
window: _("askForWindowPermission"),
|
||||||
domRect: _("askForDOMRectPermission")
|
domRect: _("askForDOMRectPermission"),
|
||||||
|
svg: _("askForSVGPermission"),
|
||||||
},
|
},
|
||||||
askStatus: {
|
askStatus: {
|
||||||
alreadyAsked: {},
|
alreadyAsked: {},
|
||||||
@ -103,7 +104,8 @@
|
|||||||
audio: _("askForAudioInputPermission"),
|
audio: _("askForAudioInputPermission"),
|
||||||
history: _("askForHistoryInputPermission"),
|
history: _("askForHistoryInputPermission"),
|
||||||
window: _("askForWindowInputPermission"),
|
window: _("askForWindowInputPermission"),
|
||||||
domRect: _("askForDOMRectInputPermission")
|
domRect: _("askForDOMRectInputPermission"),
|
||||||
|
svg: _("askForSVGInputPermission"),
|
||||||
},
|
},
|
||||||
askStatus: {
|
askStatus: {
|
||||||
alreadyAsked: {},
|
alreadyAsked: {},
|
||||||
@ -118,7 +120,8 @@
|
|||||||
audio: _("askForAudioReadoutPermission"),
|
audio: _("askForAudioReadoutPermission"),
|
||||||
history: _("askForHistoryReadoutPermission"),
|
history: _("askForHistoryReadoutPermission"),
|
||||||
window: _("askForWindowReadoutPermission"),
|
window: _("askForWindowReadoutPermission"),
|
||||||
domRect: _("askForDOMRectReadoutPermission")
|
domRect: _("askForDOMRectReadoutPermission"),
|
||||||
|
svg: _("askForSVGReadoutPermission"),
|
||||||
},
|
},
|
||||||
askStatus: {
|
askStatus: {
|
||||||
alreadyAsked: {},
|
alreadyAsked: {},
|
||||||
@ -132,11 +135,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.ask = function({window, type, api, canvas, errorStack}, {_, prefs}){
|
scope.ask = function({window, type, api, canvas, errorStack}, {_, prefs}){
|
||||||
var answer;
|
let answer;
|
||||||
var askMode = getAskMode(window, type, _);
|
const askMode = getAskMode(window, type, _);
|
||||||
var askStatus = askMode.askStatus;
|
const askStatus = askMode.askStatus;
|
||||||
var appearance = canvasAppearance(window, api, canvas);
|
const appearance = canvasAppearance(window, api, canvas);
|
||||||
var category = appearance.askCategory;
|
let category = appearance.askCategory;
|
||||||
if (prefs("askOnlyOnce") !== "no" && askStatus.alreadyAsked[category]){
|
if (prefs("askOnlyOnce") !== "no" && askStatus.alreadyAsked[category]){
|
||||||
// already asked
|
// already asked
|
||||||
appearance.reset();
|
appearance.reset();
|
||||||
@ -146,7 +149,6 @@
|
|||||||
let imgContainer = null;
|
let imgContainer = null;
|
||||||
if (type === "readout" && prefs("showCanvasWhileAsking") && canvas){
|
if (type === "readout" && prefs("showCanvasWhileAsking") && canvas){
|
||||||
try {
|
try {
|
||||||
let content = canvas.toDataURL();
|
|
||||||
let document = window.top.document;
|
let document = window.top.document;
|
||||||
imgContainer = document.createElement("div");
|
imgContainer = document.createElement("div");
|
||||||
imgContainer.style.cssText = `
|
imgContainer.style.cssText = `
|
||||||
@ -177,12 +179,12 @@
|
|||||||
imgContainer.appendChild(img);
|
imgContainer.appendChild(img);
|
||||||
document.body.appendChild(imgContainer);
|
document.body.appendChild(imgContainer);
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
// unable to read the canvas
|
// unable to read the canvas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// asking
|
// asking
|
||||||
var msg = askMode.askText[appearance.text];
|
let msg = askMode.askText[appearance.text];
|
||||||
|
|
||||||
// visible vs invisible is only calculated here correctly
|
// visible vs invisible is only calculated here correctly
|
||||||
category = appearance.text;
|
category = appearance.text;
|
||||||
@ -196,8 +198,8 @@
|
|||||||
|
|
||||||
if (prefs("askOnlyOnce") === "combined"){
|
if (prefs("askOnlyOnce") === "combined"){
|
||||||
["context", "readout", "input"].forEach(function(type){
|
["context", "readout", "input"].forEach(function(type){
|
||||||
var askMode = getAskMode(window, type, _);
|
const askMode = getAskMode(window, type, _);
|
||||||
var askStatus = askMode.askStatus;
|
const askStatus = askMode.askStatus;
|
||||||
askStatus.alreadyAsked[category] = true;
|
askStatus.alreadyAsked[category] = true;
|
||||||
askStatus.answer[category] = answer;
|
askStatus.answer[category] = answer;
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -16,12 +16,12 @@
|
|||||||
const extension = require("./extension");
|
const extension = require("./extension");
|
||||||
|
|
||||||
// Translation
|
// Translation
|
||||||
var _ = function(name, replace, translateAPI){
|
const _ = function(name, replace, translateAPI){
|
||||||
if (!translateAPI){
|
if (!translateAPI){
|
||||||
translateAPI = extension.getTranslation;
|
translateAPI = extension.getTranslation;
|
||||||
}
|
}
|
||||||
|
|
||||||
var str = translateAPI(name) || name;
|
let str = translateAPI(name) || name;
|
||||||
if (replace){
|
if (replace){
|
||||||
// replace generic content in the translation by given parameter
|
// replace generic content in the translation by given parameter
|
||||||
Object.keys(replace).forEach(function(name){
|
Object.keys(replace).forEach(function(name){
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
// Stack parsing
|
// Stack parsing
|
||||||
function parseStackEntry(entry){
|
function parseStackEntry(entry){
|
||||||
var m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
|
const m = /@(.*):(\d*):(\d*)$/.exec(entry) || ["", entry, "--", "--"];
|
||||||
return {
|
return {
|
||||||
url: m[1],
|
url: m[1],
|
||||||
line: parseInt(m[2], 10),
|
line: parseInt(m[2], 10),
|
||||||
@ -61,13 +61,12 @@
|
|||||||
// parse calling stack
|
// parse calling stack
|
||||||
const extensionID = extension.extensionID;
|
const extensionID = extension.extensionID;
|
||||||
function parseErrorStack(errorStack){
|
function parseErrorStack(errorStack){
|
||||||
var callers = errorStack.trim().split("\n");
|
const callers = errorStack.trim().split("\n").map(parseStackEntry).filter(function(caller){
|
||||||
callers = callers.map(parseStackEntry).filter(function(caller){
|
|
||||||
return !caller.url.startsWith(extensionID);
|
return !caller.url.startsWith(extensionID);
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
toString: function(translateAPI){
|
toString: function(translateAPI){
|
||||||
var msg = "";
|
let msg = "";
|
||||||
msg += "\n\n" + _("sourceOutput", undefined, translateAPI) + ": ";
|
msg += "\n\n" + _("sourceOutput", undefined, translateAPI) + ": ";
|
||||||
if (settings.showCompleteCallingStack){
|
if (settings.showCompleteCallingStack){
|
||||||
msg += callers.reduce(function(stack, c){
|
msg += callers.reduce(function(stack, c){
|
||||||
@ -82,7 +81,7 @@
|
|||||||
},
|
},
|
||||||
match: function(stackRule){
|
match: function(stackRule){
|
||||||
if (typeof stackRule.stackPosition !== "undefined"){
|
if (typeof stackRule.stackPosition !== "undefined"){
|
||||||
var pos = stackRule.stackPosition;
|
let pos = stackRule.stackPosition;
|
||||||
if (pos < 0){
|
if (pos < 0){
|
||||||
pos += callers.length;
|
pos += callers.length;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
scope.check = function check({url, errorStack}){
|
scope.check = function check({url, errorStack}){
|
||||||
url = new URL(url || "about:blank");
|
url = new URL(url || "about:blank");
|
||||||
var match = checkBoth(errorStack, url, settings.get("blockMode", url)).match(
|
const match = checkBoth(errorStack, url, settings.get("blockMode", url)).match(
|
||||||
/^(block|allow|fake|ask)(|Everything|Internal)$/
|
/^(block|allow|fake|ask)(|Everything|Internal)$/
|
||||||
);
|
);
|
||||||
if (match){
|
if (match){
|
||||||
@ -52,7 +52,7 @@
|
|||||||
logging.message("check url %s for block mode %s", url, blockMode);
|
logging.message("check url %s for block mode %s", url, blockMode);
|
||||||
switch (url.protocol){
|
switch (url.protocol){
|
||||||
case "about:":
|
case "about:":
|
||||||
if (url.href === "about:blank"){
|
if (url.pathname === "blank"){
|
||||||
logging.message("use regular mode on about:blank");
|
logging.message("use regular mode on about:blank");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@
|
|||||||
return "allowInternal";
|
return "allowInternal";
|
||||||
}
|
}
|
||||||
|
|
||||||
var mode = "block";
|
let mode = "block";
|
||||||
switch (blockMode){
|
switch (blockMode){
|
||||||
case "blockEverything":
|
case "blockEverything":
|
||||||
mode = "block";
|
mode = "block";
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -23,8 +23,8 @@
|
|||||||
this.minBoundary.nextColor = this.maxBoundary;
|
this.minBoundary.nextColor = this.maxBoundary;
|
||||||
}
|
}
|
||||||
addColor(r, g, b, a){
|
addColor(r, g, b, a){
|
||||||
var index = String.fromCharCode(r, g, b, a);
|
const index = String.fromCharCode(r, g, b, a);
|
||||||
var color = this.colors[index];
|
let color = this.colors[index];
|
||||||
if (!color){
|
if (!color){
|
||||||
color = {
|
color = {
|
||||||
index,
|
index,
|
||||||
@ -42,10 +42,10 @@
|
|||||||
if (color.count > color.nextColor.count){
|
if (color.count > color.nextColor.count){
|
||||||
// swap colors to remain in right order
|
// swap colors to remain in right order
|
||||||
// a_ -> b_ -> c -> d becomes a_ -> c -> b_ -> d
|
// a_ -> b_ -> c -> d becomes a_ -> c -> b_ -> d
|
||||||
var a_ = color.previousColor;
|
const a_ = color.previousColor;
|
||||||
var b_ = color;
|
const b_ = color;
|
||||||
var c = color.nextColor;
|
const c = color.nextColor;
|
||||||
var d = color.nextColor.nextColor;
|
const d = color.nextColor.nextColor;
|
||||||
|
|
||||||
a_.nextColor = c;
|
a_.nextColor = c;
|
||||||
c.previousColor = a_;
|
c.previousColor = a_;
|
||||||
@ -59,8 +59,8 @@
|
|||||||
}
|
}
|
||||||
getMaxColors(n){
|
getMaxColors(n){
|
||||||
n = Math.min(n, this.numberOfColors);
|
n = Math.min(n, this.numberOfColors);
|
||||||
var colors = Object.create(null);
|
const colors = Object.create(null);
|
||||||
var current = this.maxBoundary;
|
let current = this.maxBoundary;
|
||||||
for (;n && current;n -= 1){
|
for (;n && current;n -= 1){
|
||||||
current = current.previousColor;
|
current = current.previousColor;
|
||||||
colors[current.index] = current;
|
colors[current.index] = current;
|
||||||
@ -70,8 +70,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.compute = function computeColorStatistics(rawData){
|
scope.compute = function computeColorStatistics(rawData){
|
||||||
var statistic = new Statistic();
|
const statistic = new Statistic();
|
||||||
for (var i = 0, l = rawData.length; i < l; i += 4){
|
for (let i = 0, l = rawData.length; i < l; i += 4){
|
||||||
statistic.addColor(
|
statistic.addColor(
|
||||||
rawData[i + 0],
|
rawData[i + 0],
|
||||||
rawData[i + 1],
|
rawData[i + 1],
|
||||||
@ -86,10 +86,10 @@
|
|||||||
return statistic.numberOfColors > threshold;
|
return statistic.numberOfColors > threshold;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var colors = Object.create(null);
|
const colors = Object.create(null);
|
||||||
var count = 0;
|
let count = 0;
|
||||||
for (var i = 0, l = rawData.length; i < l; i += 4){
|
for (let i = 0, l = rawData.length; i < l; i += 4){
|
||||||
var index = String.fromCharCode(
|
const index = String.fromCharCode(
|
||||||
rawData[i + 0],
|
rawData[i + 0],
|
||||||
rawData[i + 1],
|
rawData[i + 1],
|
||||||
rawData[i + 2],
|
rawData[i + 2],
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -21,6 +21,10 @@
|
|||||||
const mainVersion = parseInt(info.version.replace(/\..+/, ""), 10);
|
const mainVersion = parseInt(info.version.replace(/\..+/, ""), 10);
|
||||||
canMergeHeader = mainVersion > 59;
|
canMergeHeader = mainVersion > 59;
|
||||||
blockBlob = mainVersion < 60;
|
blockBlob = mainVersion < 60;
|
||||||
|
return canMergeHeader;
|
||||||
|
}).catch(function(){
|
||||||
|
canMergeHeader = false;
|
||||||
|
blockBlob = true;
|
||||||
});
|
});
|
||||||
function setHeader(headers, header){
|
function setHeader(headers, header){
|
||||||
if (canMergeHeader){
|
if (canMergeHeader){
|
||||||
@ -43,7 +47,10 @@
|
|||||||
scope.init = function(){
|
scope.init = function(){
|
||||||
function listener(details){
|
function listener(details){
|
||||||
const headers = details.responseHeaders;
|
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: *";
|
const cspMatch = (blockBlob? "": "blob: ") + "filesystem: *";
|
||||||
logging.verbose("Adding CSP header to", details);
|
logging.verbose("Adding CSP header to", details);
|
||||||
setHeader(headers, {
|
setHeader(headers, {
|
||||||
|
287
lib/extension.js
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const browserAvailable = typeof browser !== "undefined";
|
const browserAvailable = typeof browser !== "undefined";
|
||||||
|
const logging = require("./logging");
|
||||||
|
|
||||||
scope.inBackgroundScript = !!(
|
scope.inBackgroundScript = !!(
|
||||||
browserAvailable &&
|
browserAvailable &&
|
||||||
@ -26,7 +27,56 @@
|
|||||||
return id;
|
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;
|
scope.inIncognitoContext = browserAvailable? browser.extension.inIncognitoContext: false;
|
||||||
|
|
||||||
@ -44,5 +94,238 @@
|
|||||||
};
|
};
|
||||||
Object.seal(scope.message);
|
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);
|
Object.seal(scope);
|
||||||
}());
|
}());
|
105
lib/frame.js
@ -9,18 +9,16 @@
|
|||||||
const {ask} = require("./askForPermission");
|
const {ask} = require("./askForPermission");
|
||||||
const {sha256String: hashing} = require("./hash");
|
const {sha256String: hashing} = require("./hash");
|
||||||
const {check: originalCheck, checkStack: originalCheckStack} = require("./check");
|
const {check: originalCheck, checkStack: originalCheckStack} = require("./check");
|
||||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
|
||||||
const extension = require("./extension");
|
const extension = require("./extension");
|
||||||
const iframeProtection = require("./iframeProtection");
|
const iframeProtection = require("./iframeProtection");
|
||||||
|
|
||||||
const logging = require("./logging");
|
const logging = require("./logging");
|
||||||
const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = logging;
|
logging.setPrefix("frame script");
|
||||||
setLogPrefix("frame script");
|
|
||||||
|
|
||||||
// Variable to "unload" the script
|
// Variable to "unload" the script
|
||||||
var enabled = true;
|
let enabled = true;
|
||||||
|
|
||||||
message("starting", location.href);
|
logging.message("starting", location.href);
|
||||||
|
|
||||||
function check(message){
|
function check(message){
|
||||||
if (enabled){
|
if (enabled){
|
||||||
@ -72,38 +70,40 @@
|
|||||||
}
|
}
|
||||||
computeExtensionSecret();
|
computeExtensionSecret();
|
||||||
|
|
||||||
message("open port to background script");
|
logging.message("open port to background script");
|
||||||
var port = browser.runtime.connect();
|
const port = browser.runtime.connect();
|
||||||
if (window === window.top){
|
if (window === window.top){
|
||||||
message("Is top level window -> tab had navigation -> clear page action");
|
logging.message("Is top level window -> tab had navigation -> clear page action");
|
||||||
port.postMessage({"canvasBlocker-clear-page-action": true});
|
port.postMessage({"canvasBlocker-clear-page-action": true});
|
||||||
}
|
}
|
||||||
var tabId;
|
let tabId;
|
||||||
port.onMessage.addListener(function(data){
|
port.onMessage.addListener(function(data){
|
||||||
message("Got data from port", data);
|
logging.message("Got data from port", data);
|
||||||
if (data.hasOwnProperty("tabId")){
|
if (data.hasOwnProperty("tabId")){
|
||||||
notice("my tab id is", data.tabId);
|
logging.notice("my tab id is", data.tabId);
|
||||||
tabId = data.tabId;
|
tabId = data.tabId;
|
||||||
}
|
}
|
||||||
if (data.hasOwnProperty("cookieStoreId")){
|
if (data.hasOwnProperty("cookieStoreId")){
|
||||||
notice("my tab cookie store id is", data.cookieStoreId);
|
logging.notice("my tab cookie store id is", data.cookieStoreId);
|
||||||
const {persistent: persistentRnd} = require("./randomSupplies");
|
const {persistent: persistentRnd} = require("./randomSupplies");
|
||||||
persistentRnd.setCookieStoreId(data.cookieStoreId);
|
persistentRnd.setCookieStoreId(data.cookieStoreId);
|
||||||
|
const modifiedNavigatorAPI = require("./modifiedNavigatorAPI");
|
||||||
|
modifiedNavigatorAPI.setCookieStoreId(data.cookieStoreId);
|
||||||
}
|
}
|
||||||
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
|
const persistentRndName = "persistent" + (extension.inIncognitoContext? "Incognito": "") + "Rnd";
|
||||||
if (data.hasOwnProperty(persistentRndName)){
|
if (data.hasOwnProperty(persistentRndName)){
|
||||||
const persistentRndValue = data[persistentRndName];
|
const persistentRndValue = data[persistentRndName];
|
||||||
notice("got persistent random data", persistentRndValue);
|
logging.notice("got persistent random data", persistentRndValue);
|
||||||
const {persistent: persistentRnd} = require("./randomSupplies");
|
const {persistent: persistentRnd} = require("./randomSupplies");
|
||||||
Object.keys(persistentRndValue).forEach(function(domain){
|
Object.keys(persistentRndValue).forEach(function(domain){
|
||||||
verbose("random data for", domain, persistentRndValue[domain]);
|
logging.verbose("random data for", domain, persistentRndValue[domain]);
|
||||||
persistentRnd.setDomainRnd(domain, persistentRndValue[domain]);
|
persistentRnd.setDomainRnd(domain, persistentRndValue[domain]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var notifications = [];
|
const notifications = [];
|
||||||
var notificationCounter = {};
|
const notificationCounter = {};
|
||||||
var sentAPIs = {};
|
const sentAPIs = {};
|
||||||
function notify(data){
|
function notify(data){
|
||||||
if (!settings.ignoredAPIs[data.api]){
|
if (!settings.ignoredAPIs[data.api]){
|
||||||
if (settings.storeNotificationData){
|
if (settings.storeNotificationData){
|
||||||
@ -127,17 +127,17 @@
|
|||||||
return settings.get(...args);
|
return settings.get(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const interceptedWindows = new WeakMap();
|
||||||
var interceptedWindows = new WeakMap();
|
|
||||||
function interceptWindow(window){
|
function interceptWindow(window){
|
||||||
|
let wrappedTry;
|
||||||
try {
|
try {
|
||||||
var href = window.location.href;
|
const href = window.location.href;
|
||||||
var wrappedTry = getWrapped(window);
|
wrappedTry = extension.getWrapped(window);
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
// we are unable to read the location due to SOP
|
// we are unable to read the location due to SOP
|
||||||
// therefore we also can not intercept anything.
|
// therefore we also can not intercept anything.
|
||||||
warning("NOT intercepting window due to SOP", window);
|
logging.notice("NOT intercepting window due to SOP", window);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const wrappedWindow = wrappedTry;
|
const wrappedWindow = wrappedTry;
|
||||||
@ -145,17 +145,23 @@
|
|||||||
if (!enabled || interceptedWindows.get(wrappedWindow)){
|
if (!enabled || interceptedWindows.get(wrappedWindow)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (wrappedWindow.matchMedia(extensionSecret[0]) === extensionSecret[1]){
|
const canvasBlockerData = wrappedWindow.matchMedia(extensionSecret[0]);
|
||||||
interceptedWindows.set(wrappedWindow, true);
|
if (canvasBlockerData.secret === extensionSecret[1]){
|
||||||
return false;
|
if (wrappedWindow.top === wrappedWindow){
|
||||||
|
canvasBlockerData.undoIntercept(extension.extensionID);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
interceptedWindows.set(wrappedWindow, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message("intercepting window", window);
|
logging.message("intercepting window", window);
|
||||||
intercept(
|
intercept(
|
||||||
{subject: window},
|
{subject: window},
|
||||||
{check, checkStack, ask: askWrapper, notify, prefs}
|
{check, checkStack, ask: askWrapper, notify, prefs}
|
||||||
);
|
);
|
||||||
message("prepare to intercept (i)frames.");
|
logging.message("prepare to intercept (i)frames.");
|
||||||
|
|
||||||
function interceptAllFrames(){
|
function interceptAllFrames(){
|
||||||
const currentLength = window.length;
|
const currentLength = window.length;
|
||||||
@ -169,39 +175,54 @@
|
|||||||
|
|
||||||
const matchMediaDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow, "matchMedia");
|
const matchMediaDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow, "matchMedia");
|
||||||
const originalMatchMedia = matchMediaDescriptor.value;
|
const originalMatchMedia = matchMediaDescriptor.value;
|
||||||
matchMediaDescriptor.value = exportFunction(function matchMedia(query){
|
extension.changeProperty(window, "matchMedia", {
|
||||||
if (query === extensionSecret[0]){
|
object: wrappedWindow,
|
||||||
return extensionSecret[1];
|
name: "matchMedia",
|
||||||
}
|
type: "value",
|
||||||
else {
|
changed: extension.exportFunctionWithName(function matchMedia(query){
|
||||||
return arguments.length > 1?
|
if (query === extensionSecret[0]){
|
||||||
originalMatchMedia.apply(this, wrappedWindow.Array.from(arguments)):
|
return {
|
||||||
originalMatchMedia.call(this, query);
|
secret: extensionSecret[1],
|
||||||
}
|
undoIntercept: function(token){
|
||||||
}, window);
|
if (token === extension.extensionID){
|
||||||
Object.defineProperty(wrappedWindow, "matchMedia", matchMediaDescriptor);
|
extension.revertProperties(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return arguments.length > 1?
|
||||||
|
originalMatchMedia.call(this, ...arguments):
|
||||||
|
originalMatchMedia.call(this, query);
|
||||||
|
}
|
||||||
|
}, window, originalMatchMedia.name)
|
||||||
|
});
|
||||||
|
|
||||||
interceptedWindows.set(wrappedWindow, true);
|
interceptedWindows.set(wrappedWindow, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
message("register listener for messages from background script");
|
logging.message("register listener for messages from background script");
|
||||||
extension.message.on(function(data){
|
extension.message.on(function(data){
|
||||||
if (data["canvasBlocker-unload"]){
|
if (data["canvasBlocker-unload"]){
|
||||||
|
extension.revertProperties(window);
|
||||||
|
for (let frameIndex = 0; frameIndex < window.length; frameIndex += 1){
|
||||||
|
extension.revertProperties(window[frameIndex]);
|
||||||
|
}
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
data.hasOwnProperty("canvasBlocker-sendNotifications") &&
|
data.hasOwnProperty("canvasBlocker-sendNotifications") &&
|
||||||
data["canvasBlocker-sendNotifications"] === tabId
|
data["canvasBlocker-sendNotifications"] === tabId
|
||||||
){
|
){
|
||||||
notice("sending notifications:", notifications);
|
logging.notice("sending notifications:", notifications);
|
||||||
extension.message.send({
|
extension.message.send({
|
||||||
sender: tabId,
|
sender: tabId,
|
||||||
url: window.location.href,
|
url: window.location.href,
|
||||||
"canvasBlocker-notificationCounter": notificationCounter,
|
"canvasBlocker-notificationCounter": notificationCounter,
|
||||||
"canvasBlocker-notifications": notifications
|
"canvasBlocker-notifications": notifications
|
||||||
});
|
});
|
||||||
notice("notifications sent");
|
logging.notice("notifications sent");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
44
lib/hash.js
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -20,11 +20,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
scope.sumXor = function(inputByteArray){
|
scope.sumXor = function(inputByteArray){
|
||||||
var hash = new Uint32Array(4);
|
const hash = new Uint32Array(4);
|
||||||
var sum = new Float64Array(hash.buffer, 8, 1);
|
// const sum = new Float64Array(hash.buffer, 8, 1);
|
||||||
var intView = new Uint32Array(inputByteArray.buffer);
|
const intView = new Uint32Array(inputByteArray.buffer);
|
||||||
var floatView = new Float32Array(inputByteArray.buffer);
|
// const floatView = new Float32Array(inputByteArray.buffer);
|
||||||
var length = intView.length;
|
const length = intView.length;
|
||||||
for (let i = 0; i < length; i += 1){
|
for (let i = 0; i < length; i += 1){
|
||||||
// sum[0] += floatView[i];
|
// sum[0] += floatView[i];
|
||||||
hash[0] ^= intView[i];
|
hash[0] ^= intView[i];
|
||||||
@ -34,11 +34,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
scope.hashCode = function(inputByteArray){
|
scope.hashCode = function(inputByteArray){
|
||||||
var hash = new Uint32Array(1);
|
const hash = new Uint32Array(1);
|
||||||
var intView = new Uint32Array(inputByteArray.buffer);
|
const intView = new Uint32Array(inputByteArray.buffer);
|
||||||
var length = intView.length;
|
const length = intView.length;
|
||||||
for (let i = 0; i < length; i += 1){
|
for (let i = 0; i < length; i += 1){
|
||||||
var v = hash[0];
|
const v = hash[0];
|
||||||
hash[0] = ((v << 5) - v) + intView[i];
|
hash[0] = ((v << 5) - v) + intView[i];
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
@ -81,21 +81,21 @@
|
|||||||
return function md5(inputByteArray){
|
return function md5(inputByteArray){
|
||||||
h.set(hInitial);
|
h.set(hInitial);
|
||||||
|
|
||||||
var length = inputByteArray.buffer.byteLength;
|
const length = inputByteArray.buffer.byteLength;
|
||||||
var messageBitLength = length * 8;
|
const messageBitLength = length * 8;
|
||||||
|
|
||||||
// create byte array with length dividable by 64 (512 bit)
|
// create byte array with length dividable by 64 (512 bit)
|
||||||
var neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
|
const neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
|
||||||
var messageByteArray = new Uint8Array(neededLength);
|
const messageByteArray = new Uint8Array(neededLength);
|
||||||
messageByteArray.set(new Uint8Array(inputByteArray.buffer));
|
messageByteArray.set(new Uint8Array(inputByteArray.buffer));
|
||||||
var view = new DataView(messageByteArray.buffer);
|
const view = new DataView(messageByteArray.buffer);
|
||||||
|
|
||||||
// append 10...000000
|
// append 10...000000
|
||||||
messageByteArray[length] = 0x80;
|
messageByteArray[length] = 0x80;
|
||||||
// append size in 64 bit big endian
|
// append size in 64 bit big endian
|
||||||
view.setUint32(neededLength - 8, messageBitLength, true);
|
view.setUint32(neededLength - 8, messageBitLength, true);
|
||||||
|
|
||||||
for (var i = 0; i < neededLength; i += 64){
|
for (let i = 0; i < neededLength; i += 64){
|
||||||
for (let j = 0; j < 64; j += 4){
|
for (let j = 0; j < 64; j += 4){
|
||||||
w[j / 4] = view.getUint32(i + j, true);
|
w[j / 4] = view.getUint32(i + j, true);
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@
|
|||||||
temp[4] = (temp[2] ^ (temp[1] | (~ temp[3])));
|
temp[4] = (temp[2] ^ (temp[1] | (~ temp[3])));
|
||||||
temp[5] = (7*j) % 16;
|
temp[5] = (7*j) % 16;
|
||||||
}
|
}
|
||||||
var temp_ = temp[3];
|
const temp_ = temp[3];
|
||||||
temp[3] = temp[2];
|
temp[3] = temp[2];
|
||||||
temp[2] = temp[1];
|
temp[2] = temp[1];
|
||||||
temp[1] = (leftRotate(temp[0] + temp[4] + k[j] + w[temp[5]], r[j]) + temp[1]);
|
temp[1] = (leftRotate(temp[0] + temp[4] + k[j] + w[temp[5]], r[j]) + temp[1]);
|
||||||
@ -165,14 +165,14 @@
|
|||||||
|
|
||||||
h.set(hInitial);
|
h.set(hInitial);
|
||||||
|
|
||||||
var length = inputByteArray.buffer.byteLength;
|
const length = inputByteArray.buffer.byteLength;
|
||||||
var messageBitLength = length * 8;
|
const messageBitLength = length * 8;
|
||||||
|
|
||||||
// create byte array with length dividable by 64 (512 bit)
|
// create byte array with length dividable by 64 (512 bit)
|
||||||
var neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
|
const neededLength = Math.ceil((length + 1 + 8) / 64) * 64;
|
||||||
var messageByteArray = new Uint8Array(neededLength);
|
const messageByteArray = new Uint8Array(neededLength);
|
||||||
messageByteArray.set(new Uint8Array(inputByteArray.buffer));
|
messageByteArray.set(new Uint8Array(inputByteArray.buffer));
|
||||||
var view = new DataView(messageByteArray.buffer);
|
const view = new DataView(messageByteArray.buffer);
|
||||||
|
|
||||||
// append 10...000000
|
// append 10...000000
|
||||||
messageByteArray[length] = 0x80;
|
messageByteArray[length] = 0x80;
|
||||||
|
@ -12,8 +12,42 @@
|
|||||||
scope = require.register("./iframeProtection", {});
|
scope = require.register("./iframeProtection", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.protect = function protect(window, wrappedWindow, singleCallback, allCallback){
|
const settings = require("./settings");
|
||||||
|
const extension = require("./extension");
|
||||||
|
const lists = require("./lists");
|
||||||
|
|
||||||
|
function isWhitelisted(url){
|
||||||
|
return lists.get("white").match(url) || settings.get("blockMode", url).startsWith("allow");
|
||||||
|
}
|
||||||
|
|
||||||
|
function createChangeProperty(window){
|
||||||
|
function changeProperty(object, name, type, changed){
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
|
const original = descriptor[type];
|
||||||
|
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)){
|
||||||
|
extension.revertProperties(window, "iframeProtection");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isWhitelisted(window.location)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.addEventListener("unload", function(){
|
||||||
|
extension.revertProperties(window, "iframeProtection");
|
||||||
|
});
|
||||||
|
return changeProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
function protectFrameProperties({window, wrappedWindow, changeProperty, singleCallback}){
|
||||||
["HTMLIFrameElement", "HTMLFrameElement"].forEach(function(constructorName){
|
["HTMLIFrameElement", "HTMLFrameElement"].forEach(function(constructorName){
|
||||||
const constructor = window[constructorName];
|
const constructor = window[constructorName];
|
||||||
const wrappedConstructor = wrappedWindow[constructorName];
|
const wrappedConstructor = wrappedWindow[constructorName];
|
||||||
@ -25,18 +59,16 @@
|
|||||||
const originalContentWindowGetter = contentWindowDescriptor.get;
|
const originalContentWindowGetter = contentWindowDescriptor.get;
|
||||||
const contentWindowTemp = {
|
const contentWindowTemp = {
|
||||||
get contentWindow(){
|
get contentWindow(){
|
||||||
var window = originalContentWindowGetter.call(this);
|
const window = originalContentWindowGetter.call(this);
|
||||||
if (window){
|
if (window){
|
||||||
singleCallback(window);
|
singleCallback(window);
|
||||||
}
|
}
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
contentWindowDescriptor.get = exportFunction(
|
changeProperty(wrappedConstructor.prototype, "contentWindow", "get",
|
||||||
Object.getOwnPropertyDescriptor(contentWindowTemp, "contentWindow").get,
|
Object.getOwnPropertyDescriptor(contentWindowTemp, "contentWindow").get
|
||||||
window
|
|
||||||
);
|
);
|
||||||
Object.defineProperty(wrappedConstructor.prototype, "contentWindow", contentWindowDescriptor);
|
|
||||||
|
|
||||||
const contentDocumentDescriptor = Object.getOwnPropertyDescriptor(
|
const contentDocumentDescriptor = Object.getOwnPropertyDescriptor(
|
||||||
constructor.prototype,
|
constructor.prototype,
|
||||||
@ -45,19 +77,20 @@
|
|||||||
const originalContentDocumentGetter = contentDocumentDescriptor.get;
|
const originalContentDocumentGetter = contentDocumentDescriptor.get;
|
||||||
const contentDocumentTemp = {
|
const contentDocumentTemp = {
|
||||||
get contentDocument(){
|
get contentDocument(){
|
||||||
var document = originalContentDocumentGetter.call(this);
|
const document = originalContentDocumentGetter.call(this);
|
||||||
if (document){
|
if (document){
|
||||||
singleCallback(document.defaultView);
|
singleCallback(document.defaultView);
|
||||||
}
|
}
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
contentDocumentDescriptor.get = exportFunction(
|
changeProperty(wrappedConstructor.prototype, "contentDocument", "get",
|
||||||
Object.getOwnPropertyDescriptor(contentDocumentTemp, "contentDocument").get,
|
Object.getOwnPropertyDescriptor(contentDocumentTemp, "contentDocument").get
|
||||||
window
|
|
||||||
);
|
);
|
||||||
Object.defineProperty(wrappedConstructor.prototype, "contentDocument", contentDocumentDescriptor);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function protectDOMModifications({window, wrappedWindow, changeProperty, allCallback}){
|
||||||
[
|
[
|
||||||
// useless as length could be obtained before the iframe is created and window.frames === window
|
// useless as length could be obtained before the iframe is created and window.frames === window
|
||||||
// {
|
// {
|
||||||
@ -90,120 +123,180 @@
|
|||||||
protectionDefinition.methods.forEach(function(method){
|
protectionDefinition.methods.forEach(function(method){
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, method);
|
const descriptor = Object.getOwnPropertyDescriptor(object, method);
|
||||||
const original = descriptor.value;
|
const original = descriptor.value;
|
||||||
descriptor.value = exportFunction(eval(`(function ${method}(){
|
changeProperty(object, method, "value", class {
|
||||||
const value = arguments.length?
|
[method](){
|
||||||
original.apply(this, window.Array.from(arguments)):
|
const value = arguments.length?
|
||||||
original.call(this);
|
original.call(this, ...arguments):
|
||||||
allCallback();
|
original.call(this);
|
||||||
return value;
|
allCallback();
|
||||||
})`), window);
|
return value;
|
||||||
Object.defineProperty(object, method, descriptor);
|
}
|
||||||
|
}.prototype[method]);
|
||||||
});
|
});
|
||||||
protectionDefinition.getters.forEach(function(property){
|
protectionDefinition.getters.forEach(function(property){
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
const temp = {
|
||||||
const temp = eval(`({
|
get [property](){
|
||||||
get ${property}(){
|
const ret = this[property];
|
||||||
const ret = this.${property};
|
|
||||||
allCallback();
|
allCallback();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
})`);
|
};
|
||||||
descriptor.get = exportFunction(Object.getOwnPropertyDescriptor(temp, property).get, window);
|
changeProperty(object, property, "get",
|
||||||
Object.defineProperty(object, property, descriptor);
|
Object.getOwnPropertyDescriptor(temp, property).get
|
||||||
|
);
|
||||||
});
|
});
|
||||||
protectionDefinition.setters.forEach(function(property){
|
protectionDefinition.setters.forEach(function(property){
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
||||||
const setter = descriptor.set;
|
const setter = descriptor.set;
|
||||||
const temp = eval(`({
|
const temp = {
|
||||||
set ${property}(value){
|
set [property](value){
|
||||||
const ret = setter.call(this, value);
|
const ret = setter.call(this, value);
|
||||||
// const ret = this.${property} = value;
|
// const ret = this.${property} = value;
|
||||||
allCallback();
|
allCallback();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
})`);
|
};
|
||||||
descriptor.set = exportFunction(Object.getOwnPropertyDescriptor(temp, property).set, window);
|
changeProperty(object, property, "set",
|
||||||
Object.defineProperty(object, property, descriptor);
|
Object.getOwnPropertyDescriptor(temp, property).set
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// MutationObserver to intercept iFrames while generating the DOM.
|
|
||||||
const observe = function(){
|
function enableMutationObserver({window, allCallback}){
|
||||||
var observer = new MutationObserver(allCallback);
|
const observer = new MutationObserver(allCallback);
|
||||||
var observing = false;
|
let observing = false;
|
||||||
function observe(){
|
function observe(){
|
||||||
if (
|
if (
|
||||||
!observing &&
|
!observing &&
|
||||||
window.document
|
window.document
|
||||||
){
|
){
|
||||||
observer.observe(window.document, {subtree: true, childList: true});
|
observer.observe(window.document, {subtree: true, childList: true});
|
||||||
observing = true;
|
observing = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
observe();
|
}
|
||||||
window.document.addEventListener("DOMContentLoaded", function(){
|
observe();
|
||||||
if (observing){
|
window.document.addEventListener("DOMContentLoaded", function(){
|
||||||
observer.disconnect();
|
if (observing){
|
||||||
observing = false;
|
observer.disconnect();
|
||||||
}
|
observing = false;
|
||||||
});
|
}
|
||||||
return observe;
|
});
|
||||||
}();
|
return observe;
|
||||||
|
}
|
||||||
// MutationObserver does not trigger fast enough when document.write is used
|
|
||||||
const documentWriteDescriptor = Object.getOwnPropertyDescriptor(
|
function protectDocumentWrite({window, wrappedWindow, changeProperty, observe, allCallback}){
|
||||||
|
const documentWriteDescriptorOnHTMLDocument = Object.getOwnPropertyDescriptor(
|
||||||
wrappedWindow.HTMLDocument.prototype,
|
wrappedWindow.HTMLDocument.prototype,
|
||||||
"write"
|
"write"
|
||||||
) || Object.getOwnPropertyDescriptor(
|
);
|
||||||
|
const documentWriteDescriptor = documentWriteDescriptorOnHTMLDocument || Object.getOwnPropertyDescriptor(
|
||||||
wrappedWindow.Document.prototype,
|
wrappedWindow.Document.prototype,
|
||||||
"write"
|
"write"
|
||||||
);
|
);
|
||||||
const documentWrite = documentWriteDescriptor.value;
|
const documentWrite = documentWriteDescriptor.value;
|
||||||
documentWriteDescriptor.value = exportFunction(function write(markup){
|
changeProperty(
|
||||||
for (let i = 0, l = arguments.length; i < l; i += 1){
|
documentWriteDescriptorOnHTMLDocument?
|
||||||
const str = "" + arguments[i];
|
wrappedWindow.HTMLDocument.prototype:
|
||||||
// weird problem with waterfox and google docs
|
wrappedWindow.Document.prototype,
|
||||||
const parts = (
|
"write", "value", function write(markup){
|
||||||
str.match(/^\s*<!doctype/i) &&
|
for (let i = 0, l = arguments.length; i < l; i += 1){
|
||||||
!str.match(/frame/i)
|
const str = "" + arguments[i];
|
||||||
)? [str]: str.split(/(?=<)/);
|
// weird problem with waterfox and google docs
|
||||||
const length = parts.length;
|
const parts = (
|
||||||
const scripts = window.document.getElementsByTagName("script");
|
str.match(/^\s*<!doctype/i) &&
|
||||||
for (let i = 0; i < length; i += 1){
|
!str.match(/frame/i)
|
||||||
documentWrite.call(this, parts[i]);
|
)? [str]: str.split(/(?=<)/);
|
||||||
allCallback();
|
const length = parts.length;
|
||||||
if (scripts.length && scripts[scripts.length - 1].src){
|
const scripts = window.document.getElementsByTagName("script");
|
||||||
observe();
|
for (let i = 0; i < length; i += 1){
|
||||||
|
documentWrite.call(this, parts[i]);
|
||||||
|
allCallback();
|
||||||
|
if (scripts.length && scripts[scripts.length - 1].src){
|
||||||
|
observe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, window);
|
);
|
||||||
Object.defineProperty(wrappedWindow.HTMLDocument.prototype, "write", documentWriteDescriptor);
|
|
||||||
|
|
||||||
const documentWritelnDescriptor = Object.getOwnPropertyDescriptor(
|
const documentWritelnDescriptorOnHTMLDocument = Object.getOwnPropertyDescriptor(
|
||||||
wrappedWindow.HTMLDocument.prototype,
|
wrappedWindow.HTMLDocument.prototype,
|
||||||
"writeln"
|
"writeln"
|
||||||
) || Object.getOwnPropertyDescriptor(
|
);
|
||||||
|
const documentWritelnDescriptor = documentWritelnDescriptorOnHTMLDocument || Object.getOwnPropertyDescriptor(
|
||||||
wrappedWindow.Document.prototype,
|
wrappedWindow.Document.prototype,
|
||||||
"writeln"
|
"writeln"
|
||||||
);
|
);
|
||||||
const documentWriteln = documentWritelnDescriptor.value;
|
const documentWriteln = documentWritelnDescriptor.value;
|
||||||
documentWritelnDescriptor.value = exportFunction(function writeln(markup){
|
changeProperty(
|
||||||
for (let i = 0, l = arguments.length; i < l; i += 1){
|
documentWritelnDescriptorOnHTMLDocument?
|
||||||
const str = "" + arguments[i];
|
wrappedWindow.HTMLDocument.prototype:
|
||||||
const parts = str.split(/(?=<)/);
|
wrappedWindow.Document.prototype,
|
||||||
const length = parts.length;
|
"writeln", "value", function writeln(markup){
|
||||||
const scripts = window.document.getElementsByTagName("script");
|
for (let i = 0, l = arguments.length; i < l; i += 1){
|
||||||
for (let i = 0; i < length; i += 1){
|
const str = "" + arguments[i];
|
||||||
documentWrite.call(this, parts[i]);
|
const parts = str.split(/(?=<)/);
|
||||||
allCallback();
|
const length = parts.length;
|
||||||
if (scripts.length && scripts[scripts.length - 1].src){
|
const scripts = window.document.getElementsByTagName("script");
|
||||||
observe();
|
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, "");
|
||||||
}
|
}
|
||||||
documentWriteln.call(this, "");
|
);
|
||||||
}, window);
|
}
|
||||||
Object.defineProperty(wrappedWindow.HTMLDocument.prototype, "writeln", documentWritelnDescriptor);
|
|
||||||
|
function protectWindowOpen({window, wrappedWindow, changeProperty, singleCallback}){
|
||||||
|
const windowOpenDescriptor = Object.getOwnPropertyDescriptor(
|
||||||
|
wrappedWindow,
|
||||||
|
"open"
|
||||||
|
);
|
||||||
|
const windowOpen = windowOpenDescriptor.value;
|
||||||
|
const getDocument = Object.getOwnPropertyDescriptor(
|
||||||
|
window,
|
||||||
|
"document"
|
||||||
|
).get;
|
||||||
|
changeProperty(
|
||||||
|
wrappedWindow,
|
||||||
|
"open", "value", function open(){
|
||||||
|
const newWindow = arguments.length?
|
||||||
|
windowOpen.call(this, ...arguments):
|
||||||
|
windowOpen.call(this);
|
||||||
|
if (newWindow){
|
||||||
|
// if we use windowOpen from the normal window we see some SOP errors
|
||||||
|
// BUT we need the unwrapped window...
|
||||||
|
singleCallback(getDocument.call(newWindow).defaultView);
|
||||||
|
}
|
||||||
|
return newWindow;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.protect = function protect(window, wrappedWindow, singleCallback, allCallback){
|
||||||
|
const changeProperty = createChangeProperty(window);
|
||||||
|
|
||||||
|
if (!changeProperty){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = {window, wrappedWindow, changeProperty, singleCallback, allCallback};
|
||||||
|
|
||||||
|
protectFrameProperties(api);
|
||||||
|
|
||||||
|
protectDOMModifications(api);
|
||||||
|
|
||||||
|
// MutationObserver to intercept iFrames while generating the DOM.
|
||||||
|
api.observe = enableMutationObserver(api);
|
||||||
|
|
||||||
|
// MutationObserver does not trigger fast enough when document.write is used
|
||||||
|
protectDocumentWrite(api);
|
||||||
|
|
||||||
|
protectWindowOpen(api);
|
||||||
};
|
};
|
||||||
}());
|
}());
|
654
lib/intercept.js
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
const {changedFunctions, changedGetters, setRandomSupply} = require("./modifiedAPI");
|
const {changedFunctions, changedGetters, setRandomSupply} = require("./modifiedAPI");
|
||||||
const randomSupplies = require("./randomSupplies");
|
const randomSupplies = require("./randomSupplies");
|
||||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
|
||||||
const logging = require("./logging");
|
const logging = require("./logging");
|
||||||
const settings = require("./settings");
|
const settings = require("./settings");
|
||||||
const extension = require("./extension");
|
const extension = require("./extension");
|
||||||
@ -40,322 +39,425 @@
|
|||||||
settings.on("rng", function(){
|
settings.on("rng", function(){
|
||||||
setRandomSupplyByType(settings.rng);
|
setRandomSupplyByType(settings.rng);
|
||||||
});
|
});
|
||||||
|
if (!settings.isStillDefault){
|
||||||
|
setRandomSupplyByType(settings.rng);
|
||||||
|
}
|
||||||
|
|
||||||
function getURL(window){
|
function getURL(windowToProcess){
|
||||||
let href;
|
let href;
|
||||||
try {
|
try {
|
||||||
href = window.location.href;
|
href = windowToProcess.location.href;
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
// unable to read location due to SOP
|
// unable to read location due to SOP
|
||||||
// since we are not able to do anything in that case we can allow everything
|
// since we are not able to do anything in that case we can allow everything
|
||||||
return "about:SOP";
|
return "about:SOP";
|
||||||
}
|
}
|
||||||
if (!href || href === "about:blank"){
|
if (!href || href === "about:blank"){
|
||||||
if (window !== window.parent){
|
if (windowToProcess !== windowToProcess.parent){
|
||||||
return getURL(window.parent);
|
return getURL(windowToProcess.parent);
|
||||||
}
|
}
|
||||||
else if (window.opener){
|
else if (windowToProcess.opener){
|
||||||
return getURL(window.opener);
|
return getURL(windowToProcess.opener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return href;
|
return href;
|
||||||
}
|
}
|
||||||
|
const getAllFunctionObjects = function(windowToProcess, changedFunction){
|
||||||
|
return (
|
||||||
|
Array.isArray(changedFunction.object)?
|
||||||
|
changedFunction.object:
|
||||||
|
[changedFunction.object]
|
||||||
|
).map(function(name){
|
||||||
|
if (name){
|
||||||
|
const constructor = extension.getWrapped(windowToProcess)[name];
|
||||||
|
if (constructor){
|
||||||
|
return constructor.prototype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).concat(
|
||||||
|
changedFunction.objectGetters?
|
||||||
|
changedFunction.objectGetters.map(function(objectGetter){
|
||||||
|
return objectGetter(extension.getWrapped(windowToProcess));
|
||||||
|
}):
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const forEachGetter = function(windowToProcess, callback){
|
||||||
|
changedGetters.forEach(function(changedGetter){
|
||||||
|
const name = changedGetter.name;
|
||||||
|
changedGetter.objectGetters.forEach(function(changedGetter){
|
||||||
|
const object = changedGetter(extension.getWrapped(windowToProcess));
|
||||||
|
if (object){
|
||||||
|
callback({name, object, objectGetter: changedGetter});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
scope.preIntercept = function preIntercept({subject: window}, apis){
|
const forEach = function(windowToProcess, callback){
|
||||||
if (!settings.isStillDefault){
|
forEachFunction(windowToProcess, callback);
|
||||||
logging.message("settings already loaded -> no need to pre intercept");
|
forEachGetter(windowToProcess, callback);
|
||||||
scope.intercept({subject: window}, apis);
|
};
|
||||||
|
|
||||||
|
const doRealIntercept = function(windowToProcess, apis, state){
|
||||||
|
if (!state.intercepted){
|
||||||
|
scope.intercept({subject: windowToProcess}, apis);
|
||||||
|
state.intercepted = true;
|
||||||
}
|
}
|
||||||
else {
|
};
|
||||||
logging.message("settings not loaded -> need to pre intercept");
|
const doPreIntercept = function(windowToProcess, apis, state){
|
||||||
let forceLoad = true;
|
const forceLoad = true;
|
||||||
let preIntercepted = false;
|
const originalPropertyDescriptors = {};
|
||||||
let intercepted = false;
|
const undoPreIntercept = function(){
|
||||||
const forEachFunction = function(callback){
|
if (state.preIntercepted){
|
||||||
apiNames.forEach(function(name){
|
state.preIntercepted = false;
|
||||||
const changedFunction = changedFunctions[name];
|
forEach(windowToProcess, function({name, object}){
|
||||||
(
|
const originalPropertyDescriptor = originalPropertyDescriptors[name].get(object);
|
||||||
Array.isArray(changedFunction.object)?
|
if (originalPropertyDescriptor){
|
||||||
changedFunction.object:
|
|
||||||
[changedFunction.object]
|
|
||||||
).forEach(function(object){
|
|
||||||
const constructor = getWrapped(window)[object];
|
|
||||||
if (constructor){
|
|
||||||
callback({name, object: constructor.prototype});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
changedGetters.forEach(function(changedGetter){
|
|
||||||
const name = changedGetter.name;
|
|
||||||
changedGetter.objectGetters.forEach(function(objectGetter){
|
|
||||||
const object = objectGetter(getWrapped(window));
|
|
||||||
if (object){
|
|
||||||
callback({name, object});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let originalPropertyDescriptors = {};
|
|
||||||
const doPreIntercept = function(){
|
|
||||||
if (!preIntercepted){
|
|
||||||
forEachFunction(function({name, object}){
|
|
||||||
const map = originalPropertyDescriptors[name] || new WeakMap();
|
|
||||||
originalPropertyDescriptors[name] = map;
|
|
||||||
|
|
||||||
const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, name);
|
|
||||||
if (!originalPropertyDescriptor){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
map.set(object, originalPropertyDescriptor);
|
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
object,
|
object,
|
||||||
name,
|
name,
|
||||||
{
|
originalPropertyDescriptor
|
||||||
enumerable: true,
|
|
||||||
configurable: true,
|
|
||||||
get: exportFunction(function(){
|
|
||||||
if (forceLoad){
|
|
||||||
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
|
|
||||||
undoPreIntercept();
|
|
||||||
settings.forceLoad();
|
|
||||||
doRealIntercept();
|
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
|
||||||
return descriptor.value || descriptor.get.call(this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logging.notice("API blocked (%s)", name);
|
|
||||||
const url = getURL(window);
|
|
||||||
if (!url){
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
const error = new Error();
|
|
||||||
apis.notify({
|
|
||||||
url,
|
|
||||||
errorStack: error.stack,
|
|
||||||
messageId: "preBlock",
|
|
||||||
timestamp: new Date(),
|
|
||||||
functionName: name,
|
|
||||||
dataURL: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, window),
|
|
||||||
set: exportFunction(function(){}, window)
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
preIntercepted = true;
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!state.preIntercepted){
|
||||||
|
forEach(windowToProcess, function({name, object}){
|
||||||
|
const map = originalPropertyDescriptors[name] || new WeakMap();
|
||||||
|
originalPropertyDescriptors[name] = map;
|
||||||
|
|
||||||
|
const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
|
if (!originalPropertyDescriptor){
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
const undoPreIntercept = function(){
|
map.set(object, originalPropertyDescriptor);
|
||||||
if (preIntercepted){
|
const temp = class {
|
||||||
preIntercepted = false;
|
[`get ${name}`](){
|
||||||
forEachFunction(function({name, object}){
|
if (forceLoad){
|
||||||
const originalPropertyDescriptor = originalPropertyDescriptors[name].get(object);
|
logging.warning("force load the settings. Calling stack:", (new Error()).stack);
|
||||||
if (originalPropertyDescriptor){
|
undoPreIntercept();
|
||||||
Object.defineProperty(
|
settings.forceLoad();
|
||||||
object,
|
doRealIntercept(windowToProcess, apis, state);
|
||||||
name,
|
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
||||||
originalPropertyDescriptor
|
return descriptor.value || descriptor.get.call(this);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
else {
|
||||||
}
|
logging.notice("API blocked (%s)", name);
|
||||||
};
|
const url = getURL(windowToProcess);
|
||||||
const doRealIntercept = function(){
|
if (!url){
|
||||||
if (!intercepted){
|
return undef;
|
||||||
scope.intercept({subject: window}, apis);
|
}
|
||||||
intercepted = true;
|
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: extension.exportFunctionWithName(temp[`get ${name}`], windowToProcess, `get ${name}`),
|
||||||
|
set: extension.exportFunctionWithName(temp[`set ${name}`], windowToProcess, `set ${name}`)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
state.preIntercepted = true;
|
||||||
|
}
|
||||||
|
return undoPreIntercept;
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.preIntercept = function preIntercept({subject: windowToProcess}, apis){
|
||||||
|
if (!settings.isStillDefault){
|
||||||
|
logging.message("settings already loaded -> no need to pre intercept");
|
||||||
|
scope.intercept({subject: windowToProcess}, apis);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.message("settings not loaded -> need to pre intercept");
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
preIntercepted: false,
|
||||||
|
intercepted: false
|
||||||
};
|
};
|
||||||
|
|
||||||
doPreIntercept();
|
const undoPreIntercept = doPreIntercept(windowToProcess, apis, state);
|
||||||
settings.onloaded(function(){
|
settings.onloaded(function(){
|
||||||
undoPreIntercept();
|
undoPreIntercept();
|
||||||
doRealIntercept();
|
doRealIntercept(windowToProcess, apis, state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getDataURL(object, prefs){
|
||||||
|
return (
|
||||||
|
object &&
|
||||||
|
prefs("storeImageForInspection") &&
|
||||||
|
prefs("showNotifications")?
|
||||||
|
(
|
||||||
|
object instanceof HTMLCanvasElement?
|
||||||
|
object.toDataURL():
|
||||||
|
(
|
||||||
|
object.canvas instanceof HTMLCanvasElement?
|
||||||
|
object.canvas.toDataURL():
|
||||||
|
false
|
||||||
|
)
|
||||||
|
):
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let extensionID = extension.extensionID;
|
let extensionID = extension.extensionID;
|
||||||
scope.intercept = function intercept({subject: window}, {check, checkStack, ask, notify, prefs}){
|
|
||||||
function getDataURL(object, prefs){
|
function generateChecker({
|
||||||
return (
|
name, changedFunction, siteStatus, original,
|
||||||
object &&
|
window: windowToProcess, prefs, notify, checkStack, ask
|
||||||
prefs("storeImageForInspection") &&
|
}){
|
||||||
prefs("showNotifications")?
|
return function checker(callingDepth = 3){
|
||||||
(
|
const errorStack = (new Error()).stack;
|
||||||
object instanceof HTMLCanvasElement?
|
|
||||||
object.toDataURL():
|
try {
|
||||||
(
|
// return original if the extension itself requested the function
|
||||||
object.canvas instanceof HTMLCanvasElement?
|
if (
|
||||||
object.canvas.toDataURL():
|
errorStack
|
||||||
false
|
.split("\n", callingDepth + 2)[callingDepth + 1]
|
||||||
)
|
.split("@", callingDepth + 1)[1]
|
||||||
):
|
.startsWith(extensionID)
|
||||||
false
|
){
|
||||||
);
|
return {allow: true, original, window: windowToProcess};
|
||||||
}
|
|
||||||
function generateChecker(name, changedFunction, siteStatus, original){
|
|
||||||
return function checker(callingDepth = 2){
|
|
||||||
const error = new Error();
|
|
||||||
const errorStack = error.stack;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// return original if the extension itself requested the function
|
|
||||||
if (
|
|
||||||
errorStack
|
|
||||||
.split("\n", callingDepth + 2)[callingDepth + 1]
|
|
||||||
.split("@", callingDepth + 1)[1]
|
|
||||||
.startsWith(extensionID)
|
|
||||||
){
|
|
||||||
return {allow: true, original, window};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
}
|
||||||
// stack had an unknown form
|
catch (error) {
|
||||||
}
|
// stack had an unknown form
|
||||||
if (checkStack(errorStack)){
|
}
|
||||||
return {allow: true, original, window};
|
if (checkStack(errorStack)){
|
||||||
}
|
return {allow: true, original, window: windowToProcess};
|
||||||
const funcStatus = changedFunction.getStatus(this, siteStatus, prefs);
|
}
|
||||||
|
const funcStatus = changedFunction.getStatus(this, siteStatus, prefs);
|
||||||
const This = this;
|
|
||||||
function notifyCallback(messageId){
|
const This = this;
|
||||||
notify({
|
function notifyCallback(messageId){
|
||||||
url: getURL(window),
|
notify({
|
||||||
errorStack,
|
url: getURL(windowToProcess),
|
||||||
messageId,
|
errorStack,
|
||||||
timestamp: new Date(),
|
messageId,
|
||||||
functionName: name,
|
timestamp: new Date(),
|
||||||
|
functionName: name,
|
||||||
|
api: changedFunction.api,
|
||||||
|
dataURL: getDataURL(This, prefs)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const protectedAPIFeatures = prefs("protectedAPIFeatures");
|
||||||
|
if (
|
||||||
|
funcStatus.active &&
|
||||||
|
(
|
||||||
|
!protectedAPIFeatures.hasOwnProperty(name + " @ " + changedFunction.api) ||
|
||||||
|
protectedAPIFeatures[name + " @ " + changedFunction.api]
|
||||||
|
)
|
||||||
|
){
|
||||||
|
if (funcStatus.mode === "ask"){
|
||||||
|
funcStatus.mode = ask({
|
||||||
|
window: windowToProcess,
|
||||||
|
type: changedFunction.type,
|
||||||
api: changedFunction.api,
|
api: changedFunction.api,
|
||||||
dataURL: getDataURL(This, prefs)
|
canvas: this instanceof HTMLCanvasElement?
|
||||||
|
this:
|
||||||
|
(
|
||||||
|
this &&
|
||||||
|
(this.canvas instanceof HTMLCanvasElement)?
|
||||||
|
this.canvas:
|
||||||
|
false
|
||||||
|
),
|
||||||
|
errorStack
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const protectedAPIFeatures = prefs("protectedAPIFeatures");
|
switch (funcStatus.mode){
|
||||||
if (
|
case "allow":
|
||||||
funcStatus.active &&
|
return {allow: true, original, window: windowToProcess};
|
||||||
(
|
case "fake":
|
||||||
!protectedAPIFeatures.hasOwnProperty(name) ||
|
return {
|
||||||
protectedAPIFeatures[name]
|
allow: "fake",
|
||||||
)
|
prefs,
|
||||||
){
|
notify: notifyCallback,
|
||||||
if (funcStatus.mode === "ask"){
|
window: windowToProcess,
|
||||||
funcStatus.mode = ask({
|
original
|
||||||
window: window,
|
};
|
||||||
type: changedFunction.type,
|
//case "block":
|
||||||
api: changedFunction.api,
|
default:
|
||||||
canvas: this instanceof HTMLCanvasElement?
|
return {allow: false, notify: notifyCallback};
|
||||||
this:
|
}
|
||||||
(
|
}
|
||||||
this &&
|
else {
|
||||||
(this.canvas instanceof HTMLCanvasElement)?
|
return {allow: true, original, window: windowToProcess};
|
||||||
this.canvas:
|
}
|
||||||
false
|
};
|
||||||
),
|
}
|
||||||
errorStack
|
|
||||||
});
|
function interceptFunctions(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
|
||||||
|
apiNames.forEach(function(name){
|
||||||
|
const changedFunction = changedFunctions[name];
|
||||||
|
if (changedFunction.name){
|
||||||
|
name = changedFunction.name;
|
||||||
|
}
|
||||||
|
const functionStatus = changedFunction.getStatus(undefined, siteStatus, prefs);
|
||||||
|
logging.verbose("status for", name, ":", functionStatus);
|
||||||
|
if (!functionStatus.active) return;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch (funcStatus.mode){
|
else {
|
||||||
case "allow":
|
changed = null;
|
||||||
return {allow: true, original, window};
|
|
||||||
case "fake":
|
|
||||||
return {
|
|
||||||
allow: "fake",
|
|
||||||
prefs,
|
|
||||||
notify: notifyCallback,
|
|
||||||
window,
|
|
||||||
original
|
|
||||||
};
|
|
||||||
//case "block":
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
allow: false,
|
|
||||||
notify: notifyCallback
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return {allow: true, original, window};
|
changed = extension.createProxyFunction(windowToProcess, original, extension.exportFunctionWithName(
|
||||||
|
changedFunction.fakeGenerator(checker),
|
||||||
|
windowToProcess,
|
||||||
|
original.name
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
extension.changeProperty(windowToProcess, changedFunction.api, {
|
||||||
}
|
object, name, type, changed
|
||||||
|
});
|
||||||
const siteStatus = check({url: getURL(window)});
|
});
|
||||||
logging.verbose("status for page", window, siteStatus);
|
});
|
||||||
|
}
|
||||||
|
function interceptGetters(windowToProcess, siteStatus, {checkStack, ask, notify, prefs}){
|
||||||
|
changedGetters.forEach(function(changedGetter){
|
||||||
|
const name = changedGetter.name;
|
||||||
|
const functionStatus = changedGetter.getStatus(undefined, siteStatus, prefs);
|
||||||
|
logging.verbose("status for", changedGetter, ":", functionStatus);
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
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){
|
||||||
|
const siteStatus = apis.check({url: getURL(windowToProcess)});
|
||||||
|
logging.verbose("status for page", windowToProcess, siteStatus);
|
||||||
if (siteStatus.mode !== "allow"){
|
if (siteStatus.mode !== "allow"){
|
||||||
apiNames.forEach(function(name){
|
interceptFunctions(windowToProcess, siteStatus, apis);
|
||||||
const changedFunction = changedFunctions[name];
|
interceptGetters(windowToProcess, siteStatus, apis);
|
||||||
const functionStatus = changedFunction.getStatus(undefined, siteStatus, prefs);
|
|
||||||
logging.verbose("status for", name, ":", functionStatus);
|
|
||||||
if (functionStatus.active){
|
|
||||||
(
|
|
||||||
Array.isArray(changedFunction.object)?
|
|
||||||
changedFunction.object:
|
|
||||||
[changedFunction.object]
|
|
||||||
).forEach(function(object){
|
|
||||||
const constructor = getWrapped(window)[object];
|
|
||||||
if (constructor){
|
|
||||||
const original = constructor.prototype[name];
|
|
||||||
const checker = generateChecker(name, changedFunction, siteStatus, original);
|
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, name);
|
|
||||||
if (descriptor){
|
|
||||||
if (descriptor.hasOwnProperty("value")){
|
|
||||||
if (changedFunction.fakeGenerator){
|
|
||||||
descriptor.value = exportFunction(
|
|
||||||
changedFunction.fakeGenerator(checker, original, window),
|
|
||||||
window
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
descriptor.value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
descriptor.get = exportFunction(function(){
|
|
||||||
return exportFunction(
|
|
||||||
changedFunction.fakeGenerator(checker),
|
|
||||||
window
|
|
||||||
);
|
|
||||||
}, window);
|
|
||||||
}
|
|
||||||
Object.defineProperty(constructor.prototype, name, descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
changedGetters.forEach(function(changedGetter){
|
|
||||||
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(window));
|
|
||||||
if (object){
|
|
||||||
const descriptor = Object.getOwnPropertyDescriptor(object, name);
|
|
||||||
if (descriptor && descriptor.hasOwnProperty("get")){
|
|
||||||
const original = descriptor.get;
|
|
||||||
const checker = generateChecker(name, changedGetter, siteStatus, original);
|
|
||||||
const getter = changedGetter.getterGenerator(checker, original, window);
|
|
||||||
descriptor.get = exportFunction(getter, window);
|
|
||||||
|
|
||||||
if (descriptor.hasOwnProperty("set") && changedGetter.setterGenerator){
|
|
||||||
const setter = changedGetter.setterGenerator(window, descriptor.set, prefs);
|
|
||||||
descriptor.set = exportFunction(setter, window);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(object, name, descriptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logging.error("Try to fake non getter property:", changedGetter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}());
|
}());
|
61
lib/lists.js
@ -6,7 +6,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -14,11 +14,12 @@
|
|||||||
scope = require.register("./lists", {});
|
scope = require.register("./lists", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings = require("./settings");
|
const settings = require("./settings");
|
||||||
|
const logging = require("./logging");
|
||||||
|
|
||||||
|
|
||||||
function getDomainRegExpList(domainList){
|
function getDomainRegExpList(domainList){
|
||||||
var list = domainList
|
const list = domainList
|
||||||
.split(",")
|
.split(",")
|
||||||
.map(function(entry){
|
.map(function(entry){
|
||||||
return entry.replace(/^\s+|\s+$/g, "");
|
return entry.replace(/^\s+|\s+$/g, "");
|
||||||
@ -27,15 +28,28 @@
|
|||||||
return !!entry.length;
|
return !!entry.length;
|
||||||
})
|
})
|
||||||
.map(function(entry){
|
.map(function(entry){
|
||||||
var regExp;
|
let regExp;
|
||||||
var domain = !!entry.match(/^[A-Za-z0-9_.-]+$/);
|
const domain = !!entry.match(/^[A-Za-z0-9_.*-]+$/);
|
||||||
if (domain){
|
if (domain){
|
||||||
regExp = new RegExp("(?:^|\\.)" + entry.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$", "i");
|
regExp = new RegExp(
|
||||||
|
"(?:^|\\.)" + entry.replace(/([\\+?[^\]$(){}=!|.])/g, "\\$1").replace(/\*/g, ".+") + "\\.?$",
|
||||||
|
"i"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
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 {
|
return {
|
||||||
|
value: entry,
|
||||||
match: function(url){
|
match: function(url){
|
||||||
if (domain){
|
if (domain){
|
||||||
return (url.hostname || "").match(regExp);
|
return (url.hostname || "").match(regExp);
|
||||||
@ -59,7 +73,7 @@
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lists = {
|
const lists = {
|
||||||
white: [],
|
white: [],
|
||||||
sessionWhite: [],
|
sessionWhite: [],
|
||||||
"ignore": [],
|
"ignore": [],
|
||||||
@ -81,9 +95,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function updateStackList(value){
|
function updateStackList(value){
|
||||||
var list;
|
let list;
|
||||||
try {
|
try {
|
||||||
var data = JSON.parse(value);
|
let data = JSON.parse(value);
|
||||||
if (!Array.isArray(data)){
|
if (!Array.isArray(data)){
|
||||||
data = [data];
|
data = [data];
|
||||||
}
|
}
|
||||||
@ -91,7 +105,7 @@
|
|||||||
return typeof entry === "object" && typeof entry.url === "string";
|
return typeof entry === "object" && typeof entry.url === "string";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(error){
|
||||||
list = [];
|
list = [];
|
||||||
}
|
}
|
||||||
list.match = function(stack){
|
list.match = function(stack){
|
||||||
@ -109,20 +123,33 @@
|
|||||||
|
|
||||||
scope.get = function getList(type){
|
scope.get = function getList(type){
|
||||||
if (type === "white"){
|
if (type === "white"){
|
||||||
var combined = lists.white.slice().concat(lists.sessionWhite);
|
const combined = lists.white.slice().concat(lists.sessionWhite);
|
||||||
return addMatchToList(combined);
|
return addMatchToList(combined);
|
||||||
}
|
}
|
||||||
return lists[type];
|
return lists[type];
|
||||||
};
|
};
|
||||||
scope.appendTo = function appendToList(type, entry){
|
scope.appendTo = async function appendToList(type, entry){
|
||||||
var oldValue = settings[type + "List"];
|
const oldValue = settings[type + "List"];
|
||||||
return settings.set(type + "List", oldValue + (oldValue? ",": "") + entry).then(function(){
|
await settings.set(type + "List", oldValue + (oldValue? ",": "") + entry);
|
||||||
return updateList(type);
|
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.update = updateList;
|
||||||
scope.updateAll = function updateAllLists(){
|
scope.updateAll = function updateAllLists(){
|
||||||
updateList("white");
|
updateList("white");
|
||||||
|
updateList("sessionWhite");
|
||||||
updateList("ignore");
|
updateList("ignore");
|
||||||
updateList("black");
|
updateList("black");
|
||||||
updateStackList(settings.stackList);
|
updateStackList(settings.stackList);
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
/* eslint no-console: off */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -14,24 +13,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let settings = false;
|
let settings = false;
|
||||||
scope.setSettings = function(realSettings){
|
scope.setSettings = async function(realSettings){
|
||||||
if (!settings){
|
if (!settings){
|
||||||
settings = realSettings;
|
settings = realSettings;
|
||||||
settings.loaded.then(scope.clearQueue);
|
await settings.loaded;
|
||||||
|
return scope.clearQueue();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
warning("logging: Settings can only be set once.");
|
warning("logging: Settings can only be set once.");
|
||||||
|
return settings.loaded;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var prefix = "";
|
let prefix = "";
|
||||||
|
|
||||||
function leftPad(str, char, pad){
|
function leftPad(str, char, pad){
|
||||||
str = "" + str;
|
str = "" + str;
|
||||||
return char.repeat(pad - str.length) + str;
|
return char.repeat(pad - str.length) + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
var colors = {
|
const colors = {
|
||||||
1: "color: red",
|
1: "color: red",
|
||||||
25: "color: orange",
|
25: "color: orange",
|
||||||
50: "",
|
50: "",
|
||||||
@ -40,7 +41,7 @@
|
|||||||
999: "background-color: lightgray"
|
999: "background-color: lightgray"
|
||||||
};
|
};
|
||||||
|
|
||||||
var queue = [];
|
let queue = [];
|
||||||
function performLog(level, args, date){
|
function performLog(level, args, date){
|
||||||
if (!date){
|
if (!date){
|
||||||
date = new Date();
|
date = new Date();
|
||||||
@ -50,7 +51,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (settings.logLevel >= level){
|
if (settings.logLevel >= level){
|
||||||
var pre = "%c[CanvasBlocker] ";
|
let pre = "%c[CanvasBlocker] ";
|
||||||
if (prefix){
|
if (prefix){
|
||||||
pre += prefix + ": ";
|
pre += prefix + ": ";
|
||||||
}
|
}
|
||||||
@ -71,15 +72,16 @@
|
|||||||
args.unshift(colors[level] || "");
|
args.unshift(colors[level] || "");
|
||||||
args.unshift(pre);
|
args.unshift(pre);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log.apply(console, args);
|
console.log.apply(console, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function error (...args){performLog(1, args);}
|
function error (...args){performLog(1, args);}
|
||||||
function warning(...args){performLog(25, args);}
|
function warning(...args){performLog(25, args);}
|
||||||
function message(...args){performLog(50, args);}
|
function message(...args){performLog(50, args);}
|
||||||
function notice (...args){performLog(75, args);}
|
function notice (...args){performLog(75, args);}
|
||||||
function verbose(...args){performLog(100, args);}
|
function verbose(...args){performLog(100, args);}
|
||||||
function metaLog(...args){performLog(999, args);}
|
function metaLog(...args){performLog(999, args);}
|
||||||
|
|
||||||
@ -94,7 +96,7 @@
|
|||||||
scope.clearQueue = function(){
|
scope.clearQueue = function(){
|
||||||
if (queue.length){
|
if (queue.length){
|
||||||
metaLog("clear logging queue");
|
metaLog("clear logging queue");
|
||||||
var tmp = queue;
|
const tmp = queue;
|
||||||
queue = [];
|
queue = [];
|
||||||
tmp.forEach(function(item){
|
tmp.forEach(function(item){
|
||||||
performLog(item.level, item.args, item.date);
|
performLog(item.level, item.args, item.date);
|
||||||
|
221
lib/main.js
@ -6,25 +6,80 @@
|
|||||||
|
|
||||||
const settings = require("./settings");
|
const settings = require("./settings");
|
||||||
const logging = require("./logging");
|
const logging = require("./logging");
|
||||||
const {error, warning, message, notice, verbose, } = logging;
|
|
||||||
logging.setPrefix("main script");
|
logging.setPrefix("main script");
|
||||||
const persistentRndStorage = require("./persistentRndStorage");
|
const persistentRndStorage = require("./persistentRndStorage");
|
||||||
const notification = require("./notification");
|
const notification = require("./notification");
|
||||||
|
const mobile = require("./mobile");
|
||||||
|
const extension = require("./extension");
|
||||||
|
|
||||||
message("start of background script");
|
const registerSettingsContentScript = (function(){
|
||||||
message("waiting for settings to be loaded");
|
let unregisterSettingsContentScript = function(){};
|
||||||
|
let lastRegistering;
|
||||||
|
return async function registerSettingsContentScript(){
|
||||||
|
logging.message("Register content script for the settings.");
|
||||||
|
logging.verbose("Unregister old content script, if present.");
|
||||||
|
unregisterSettingsContentScript();
|
||||||
|
const data = {};
|
||||||
|
settings.forEach(function(def){
|
||||||
|
data[def.name] = def.get();
|
||||||
|
});
|
||||||
|
lastRegistering = data;
|
||||||
|
const api = await browser.contentScripts.register({
|
||||||
|
matches: ["<all_urls>"],
|
||||||
|
matchAboutBlank: true,
|
||||||
|
allFrames: true,
|
||||||
|
runAt: "document_start",
|
||||||
|
js: [{
|
||||||
|
code: `(function(settingsData){
|
||||||
|
if (typeof require !== "undefined"){
|
||||||
|
const settings = require("./settings");
|
||||||
|
const logging = require("./logging");
|
||||||
|
if (settings.init(settingsData)){
|
||||||
|
logging.message("Initialized settings by dynamic content script.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.warning("Dynamic content script was too late to provide settings.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!window.scope){
|
||||||
|
window.scope = {};
|
||||||
|
}
|
||||||
|
window.scope.settingsData = settingsData;
|
||||||
|
console.warn(
|
||||||
|
"[CanvasBlocker] invalid content script order: require not defined at",
|
||||||
|
window.location.href
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}(${JSON.stringify(data)}))`
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}());
|
||||||
|
|
||||||
|
logging.message("start of background script");
|
||||||
|
logging.message("waiting for settings to be loaded");
|
||||||
settings.onloaded(function(){
|
settings.onloaded(function(){
|
||||||
notice("everything loaded");
|
logging.notice("everything loaded");
|
||||||
|
|
||||||
message("perform startup reset");
|
logging.message("perform startup reset");
|
||||||
settings.startupReset();
|
settings.startupReset();
|
||||||
|
|
||||||
persistentRndStorage.init();
|
persistentRndStorage.init();
|
||||||
|
|
||||||
message("register non port message listener");
|
logging.message("register non port message listener");
|
||||||
browser.runtime.onMessage.addListener(function(data){
|
browser.runtime.onMessage.addListener(async function(data){
|
||||||
notice("got data without port", data);
|
logging.notice("got data without port", data);
|
||||||
var keys = Object.keys(data);
|
const keys = Object.keys(data);
|
||||||
if (data["canvasBlocker-new-domain-rnd"]){
|
if (data["canvasBlocker-new-domain-rnd"]){
|
||||||
persistentRndStorage.setDomainData(
|
persistentRndStorage.setDomainData(
|
||||||
data["canvasBlocker-new-domain-rnd"].domain,
|
data["canvasBlocker-new-domain-rnd"].domain,
|
||||||
@ -36,7 +91,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data["canvasBlocker-clear-domain-rnd"]){
|
if (data["canvasBlocker-clear-domain-rnd"]){
|
||||||
persistentRndStorage.clear();
|
persistentRndStorage.clear(data["canvasBlocker-clear-domain-rnd"] === "force");
|
||||||
if (keys.length === 1){
|
if (keys.length === 1){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -47,31 +102,30 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notice("pass the message to the tabs");
|
logging.notice("pass the message to the tabs");
|
||||||
browser.tabs.query({}).then(function(tabs){
|
const tabs = await browser.tabs.query({});
|
||||||
tabs.forEach(function(tab){
|
tabs.forEach(function(tab){
|
||||||
browser.tabs.sendMessage(tab.id, data);
|
browser.tabs.sendMessage(tab.id, data);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
message("register port listener");
|
logging.message("register port listener");
|
||||||
browser.runtime.onConnect.addListener(function(port){
|
browser.runtime.onConnect.addListener(function(port){
|
||||||
notice("got port", port);
|
logging.notice("got port", port);
|
||||||
if (!port.sender.tab){
|
if (!port.sender.tab){
|
||||||
notice("got port without tab = Firefox bug:", port);
|
logging.notice("got port without tab = Firefox bug:", port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
verbose("send back the tab id", port.sender.tab.id);
|
logging.verbose("send back the tab id", port.sender.tab.id);
|
||||||
verbose("send back the tab cookie store id", port.sender.tab.cookieStoreId);
|
logging.verbose("send back the tab cookie store id", port.sender.tab.cookieStoreId);
|
||||||
verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd);
|
logging.verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd);
|
||||||
port.postMessage({
|
port.postMessage({
|
||||||
tabId: port.sender.tab.id,
|
tabId: port.sender.tab.id,
|
||||||
cookieStoreId: port.sender.tab.cookieStoreId,
|
cookieStoreId: port.sender.tab.cookieStoreId || "",
|
||||||
persistentRnd: persistentRndStorage.persistentRnd,
|
persistentRnd: persistentRndStorage.persistentRnd,
|
||||||
persistentIncognitoRnd: persistentRndStorage.persistentIncognitoRnd
|
persistentIncognitoRnd: persistentRndStorage.persistentIncognitoRnd
|
||||||
});
|
});
|
||||||
var url = new URL(port.sender.url);
|
const url = new URL(port.sender.url);
|
||||||
port.onMessage.addListener(function(data){
|
port.onMessage.addListener(function(data){
|
||||||
if (data.hasOwnProperty("canvasBlocker-notify")){
|
if (data.hasOwnProperty("canvasBlocker-notify")){
|
||||||
notification.show(port.sender.tab.id, url, data["canvasBlocker-notify"].api);
|
notification.show(port.sender.tab.id, url, data["canvasBlocker-notify"].api);
|
||||||
@ -79,76 +133,25 @@
|
|||||||
if (data.hasOwnProperty("canvasBlocker-clear-page-action")){
|
if (data.hasOwnProperty("canvasBlocker-clear-page-action")){
|
||||||
notification.hide(port.sender.tab.id, url);
|
notification.hide(port.sender.tab.id, url);
|
||||||
}
|
}
|
||||||
verbose("got data", data, "from port", port);
|
logging.verbose("got data", data, "from port", port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
message("register storage change event listener");
|
logging.message("register storage change event listener");
|
||||||
|
|
||||||
if (browser.contentScripts){
|
if (browser.contentScripts){
|
||||||
let unregister = function(){};
|
registerSettingsContentScript();
|
||||||
let lastRegistering;
|
settings.on("any", registerSettingsContentScript);
|
||||||
const register = function register(){
|
|
||||||
logging.message("Register content script for the settings.");
|
|
||||||
logging.verbose("Unregister old content script, if present.");
|
|
||||||
unregister();
|
|
||||||
var data = {};
|
|
||||||
settings.forEach(function(def){
|
|
||||||
data[def.name] = def.get();
|
|
||||||
});
|
|
||||||
lastRegistering = data;
|
|
||||||
browser.contentScripts.register({
|
|
||||||
matches: ["<all_urls>"],
|
|
||||||
matchAboutBlank: true,
|
|
||||||
allFrames: true,
|
|
||||||
runAt: "document_start",
|
|
||||||
js: [{
|
|
||||||
code: `(function(settingsData){
|
|
||||||
if (typeof require !== "undefined"){
|
|
||||||
const settings = require("./settings");
|
|
||||||
const logging = require("./logging");
|
|
||||||
if (settings.init(settingsData)){
|
|
||||||
logging.message("Initialized settings by dynamic content script.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logging.error("Dynamic content script was too late to provide settings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!window.scope){
|
|
||||||
window.scope = {};
|
|
||||||
}
|
|
||||||
window.scope.settingsData = settingsData;
|
|
||||||
console.warn(
|
|
||||||
"[CanvasBlocker] invalid content script order: require not defined at",
|
|
||||||
window.location.href
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}(${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 {
|
|
||||||
unregister = api.unregister;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
register();
|
|
||||||
settings.on("any", register);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logging.error("Old Firefox does not support browser.contentScript.register()");
|
logging.error("Old Firefox does not support browser.contentScript.register()");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
message("Initialize data-URL workaround.");
|
logging.message("Initialize data-URL workaround.");
|
||||||
require("./dataUrls").init();
|
require("./dataUrls").init();
|
||||||
|
|
||||||
message("Initialize navigator HTTP header protection.");
|
logging.message("Initialize navigator HTTP header protection.");
|
||||||
require("./navigator").init();
|
require("./navigator").init();
|
||||||
|
|
||||||
browser.runtime.onInstalled.addListener(function(details){
|
browser.runtime.onInstalled.addListener(function(details){
|
||||||
@ -159,27 +162,71 @@
|
|||||||
!browser.pageAction.openPopup
|
!browser.pageAction.openPopup
|
||||||
){
|
){
|
||||||
browser.tabs.create({
|
browser.tabs.create({
|
||||||
url: browser.extension.getURL("options/options.html?notice=" + reason)
|
url: extension.getURL("options/options.html?notice=" + reason)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (details.reason){
|
switch (details.reason){
|
||||||
case "install":
|
case "install":
|
||||||
message("CanvasBlocker installed");
|
logging.message("CanvasBlocker installed");
|
||||||
openOptions(details.reason);
|
openOptions(details.reason);
|
||||||
browser.tabs.create({
|
settings.onloaded(function(){
|
||||||
url: browser.extension.getURL("options/presets.html?notice=" + details.reason)
|
if (settings.showPresetsOnInstallation){
|
||||||
|
browser.tabs.create({
|
||||||
|
url: extension.getURL("options/presets.html?notice=" + details.reason)
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "update":
|
case "update":
|
||||||
settings.onloaded(function(){
|
settings.onloaded(function(){
|
||||||
if (!settings.dontShowOptionsOnUpdate){
|
if (!settings.dontShowOptionsOnUpdate){
|
||||||
message("CanvasBlocker updated");
|
logging.message("CanvasBlocker updated");
|
||||||
openOptions(details.reason);
|
openOptions(details.reason);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mobile default settings
|
||||||
|
mobile.ifMobile(async function(){
|
||||||
|
const settings = await browser.storage.local.get();
|
||||||
|
mobile.applyMobileDefaults(settings);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
message("end");
|
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");
|
||||||
}());
|
}());
|
||||||
|
53
lib/mobile.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* 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("./mobile", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = require("./settings");
|
||||||
|
const settingDefinitions = require("./settingDefinitions");
|
||||||
|
|
||||||
|
scope.isMobile = async function isMobile(){
|
||||||
|
const platformInfo = await browser.runtime.getPlatformInfo();
|
||||||
|
if (platformInfo && platformInfo.os === "android"){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// todo: proper mobile check (e.g. over browser.runtime.getBrowserInfo()) and no feature check
|
||||||
|
return !browser.pageAction ||
|
||||||
|
!browser.pageAction.show ||
|
||||||
|
!browser.pageAction.openPopup
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 = async function applyMobileDefaults(storage = false){
|
||||||
|
await Promise.all(settingDefinitions.filter(function(definition){
|
||||||
|
return definition.hasOwnProperty("mobileDefaultValue") && (
|
||||||
|
!storage ||
|
||||||
|
!storage.hasOwnProperty(definition.name)
|
||||||
|
);
|
||||||
|
}).map(function(definition){
|
||||||
|
return settings.set(definition.name, definition.mobileDefaultValue);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}());
|
@ -96,8 +96,7 @@
|
|||||||
const parentTop = getGlobalOffsetTop(parent) - getGlobalScrollTop(parent);
|
const parentTop = getGlobalOffsetTop(parent) - getGlobalScrollTop(parent);
|
||||||
const parentHeight = parent.offsetHeight;
|
const parentHeight = parent.offsetHeight;
|
||||||
const height = dialog.offsetHeight;
|
const height = dialog.offsetHeight;
|
||||||
const top = Math.max(
|
const top = Math.max(0,
|
||||||
0,
|
|
||||||
Math.min(
|
Math.min(
|
||||||
container.offsetHeight - height,
|
container.offsetHeight - height,
|
||||||
parentTop + parentHeight / 2 - height / 2
|
parentTop + parentHeight / 2 - height / 2
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -39,5 +39,8 @@
|
|||||||
appendModified(require("./modifiedHistoryAPI"));
|
appendModified(require("./modifiedHistoryAPI"));
|
||||||
appendModified(require("./modifiedWindowAPI"));
|
appendModified(require("./modifiedWindowAPI"));
|
||||||
appendModified(require("./modifiedDOMRectAPI"));
|
appendModified(require("./modifiedDOMRectAPI"));
|
||||||
|
appendModified(require("./modifiedSVGAPI"));
|
||||||
|
appendModified(require("./modifiedTextMetricsAPI"));
|
||||||
appendModified(require("./modifiedNavigatorAPI"));
|
appendModified(require("./modifiedNavigatorAPI"));
|
||||||
|
appendModified(require("./modifiedScreenAPI"));
|
||||||
}());
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -12,16 +12,12 @@
|
|||||||
scope = require.register("./modifiedAPIFunctions", {});
|
scope = require.register("./modifiedAPIFunctions", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.getWrapped = function getWrapped(obj){
|
|
||||||
return obj && (obj.wrappedJSObject || obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.checkerWrapper = function checkerWrapper(checker, object, args, callback){
|
scope.checkerWrapper = function checkerWrapper(checker, object, args, callback){
|
||||||
const check = checker.call(object);
|
const check = checker.call(object);
|
||||||
if (check.allow){
|
if (check.allow){
|
||||||
if (check.allow === true){
|
if (check.allow === true){
|
||||||
return args.length?
|
return args.length?
|
||||||
check.original.apply(object, check.window.Array.from(args)):
|
check.original.call(object, ...args):
|
||||||
check.original.call(object);
|
check.original.call(object);
|
||||||
}
|
}
|
||||||
return callback.call(object, args, check);
|
return callback.call(object, args, check);
|
||||||
@ -30,9 +26,17 @@
|
|||||||
return undefined;
|
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){
|
scope.setFunctionProperties = function setFunctionProperties(functions, data){
|
||||||
Object.keys(functions).forEach(function(key){
|
Object.keys(functions).forEach(function(key){
|
||||||
var func = functions[key];
|
const func = functions[key];
|
||||||
["type", "api", "getStatus"].forEach(function(property){
|
["type", "api", "getStatus"].forEach(function(property){
|
||||||
if (data[property] && !func[property]){
|
if (data[property] && !func[property]){
|
||||||
func[property] = data[property];
|
func[property] = data[property];
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -12,25 +12,24 @@
|
|||||||
scope = require.register("./modifiedAudioAPI", {});
|
scope = require.register("./modifiedAudioAPI", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const logging = require("./logging");
|
|
||||||
const {sha256String: hashing} = require("./hash");
|
const {sha256String: hashing} = require("./hash");
|
||||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
const {checkerWrapper, setFunctionProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
|
||||||
var randomSupply = null;
|
let randomSupply = null;
|
||||||
|
|
||||||
const getAudioFakeRate = function(){
|
const getAudioFakeRate = function(){
|
||||||
const audioFakeRate = {
|
const audioFakeRate = {
|
||||||
"1": function(array){return 1;},
|
"1": function(){return 1;},
|
||||||
"10": function(array){return 10;},
|
"10": function(){return 10;},
|
||||||
"100": function(array){return 100;},
|
"100": function(){return 100;},
|
||||||
"1000": function(array){return 1000;},
|
"1000": function(){return 1000;},
|
||||||
"0.1%": function(array){return array.length / 1000;},
|
"0.1%": function(array){return array.length / 1000;},
|
||||||
"1%": function(array){return array.length / 100;},
|
"1%": function(array){return array.length / 100;},
|
||||||
"10%": function(array){return array.length / 10;},
|
"10%": function(array){return array.length / 10;},
|
||||||
"100%": function(array){return array.length;},
|
"100%": function(array){return array.length;},
|
||||||
};
|
};
|
||||||
return function getAudioFakeRate(array, prefs){
|
return function getAudioFakeRate(array, prefs){
|
||||||
var func = audioFakeRate[prefs("audioFakeRate")];
|
const func = audioFakeRate[prefs("audioFakeRate")];
|
||||||
if (typeof func === "function"){
|
if (typeof func === "function"){
|
||||||
return func(array);
|
return func(array);
|
||||||
}
|
}
|
||||||
@ -66,18 +65,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function forEachIndex(array, prefs, callback){
|
function forEachIndex(array, prefs, callback){
|
||||||
var length = array.length;
|
const length = array.length;
|
||||||
var rate = getAudioFakeRate(array, prefs);
|
const rate = getAudioFakeRate(array, prefs);
|
||||||
var start = 0;
|
let start = 0;
|
||||||
forEachFixedIndex(prefs, function(index){
|
forEachFixedIndex(prefs, function(index){
|
||||||
callback(index, start);
|
callback(index, start);
|
||||||
start += 1;
|
start += 1;
|
||||||
});
|
});
|
||||||
if (start < rate){
|
if (start < rate){
|
||||||
var delta = Math.floor(length / (rate - start));
|
const delta = Math.floor(length / (rate - start));
|
||||||
var indexRng = randomSupply.getIndexRng(1, length - delta * (rate - start - 1), window);
|
const indexRng = randomSupply.getIndexRng(1, length - delta * (rate - start - 1), window);
|
||||||
var offset = indexRng(0);
|
let offset = indexRng(0);
|
||||||
for (var i = start; i < rate; i += 1){
|
for (let i = start; i < rate; i += 1){
|
||||||
callback(offset, i);
|
callback(offset, i);
|
||||||
offset += delta;
|
offset += delta;
|
||||||
}
|
}
|
||||||
@ -88,7 +87,7 @@
|
|||||||
const intCache = Object.create(null);
|
const intCache = Object.create(null);
|
||||||
|
|
||||||
function arrayHasAnyNonZero(array){
|
function arrayHasAnyNonZero(array){
|
||||||
for (var i = 0, l = array.length; i < l; i += 1){
|
for (let i = 0, l = array.length; i < l; i += 1){
|
||||||
if (array[i]){
|
if (array[i]){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -105,9 +104,9 @@
|
|||||||
cached = floatCache[hash];
|
cached = floatCache[hash];
|
||||||
}
|
}
|
||||||
if (!cached){
|
if (!cached){
|
||||||
var rate = getAudioFakeRate(array, prefs);
|
const rate = getAudioFakeRate(array, prefs);
|
||||||
var noiseLevel = getAudioNoiseLevel(prefs);
|
const noiseLevel = getAudioNoiseLevel(prefs);
|
||||||
var rng = randomSupply.getRng(rate, window);
|
const rng = randomSupply.getRng(rate, window);
|
||||||
forEachIndex(array, prefs, function(index, i){
|
forEachIndex(array, prefs, function(index, i){
|
||||||
let value;
|
let value;
|
||||||
if (array[index] !== 0){
|
if (array[index] !== 0){
|
||||||
@ -137,8 +136,8 @@
|
|||||||
cached = intCache[hash];
|
cached = intCache[hash];
|
||||||
}
|
}
|
||||||
if (!cached){
|
if (!cached){
|
||||||
var rate = getAudioFakeRate(array, prefs);
|
const rate = getAudioFakeRate(array, prefs);
|
||||||
var rng = randomSupply.getValueRng(rate, window);
|
const rng = randomSupply.getValueRng(rate, window);
|
||||||
forEachIndex(array, prefs, function(index, i){
|
forEachIndex(array, prefs, function(index, i){
|
||||||
array[index] = rng(array[index], i);
|
array[index] = rng(array[index], i);
|
||||||
});
|
});
|
||||||
@ -157,26 +156,23 @@
|
|||||||
randomSupply = supply;
|
randomSupply = supply;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getStatus(obj, status, prefs){
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = prefs("protectAudio", status.url);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getChannelDataAlreadyFakedArrays = new WeakMap();
|
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
|
// changed functions and their fakes
|
||||||
scope.changedFunctions = {
|
scope.changedFunctions = {
|
||||||
getFloatFrequencyData: {
|
getFloatFrequencyData: {
|
||||||
object: ["AnalyserNode"],
|
object: ["AnalyserNode"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getFloatFrequencyData(array){
|
return function getFloatFrequencyData(array){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments,
|
||||||
var {prefs, notify, window, original} = check;
|
fakeArrayCheckerCallback.bind(this, array, fakeFloat32Array)
|
||||||
notify("fakedAudioReadout");
|
);
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
fakeFloat32Array(array, window, prefs);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -184,13 +180,9 @@
|
|||||||
object: ["AnalyserNode"],
|
object: ["AnalyserNode"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getByteFrequencyData(array){
|
return function getByteFrequencyData(array){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments,
|
||||||
var {prefs, notify, window, original} = check;
|
fakeArrayCheckerCallback.bind(this, array, fakeUint8Array)
|
||||||
notify("fakedAudioReadout");
|
);
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
fakeUint8Array(array, window, prefs);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -198,13 +190,9 @@
|
|||||||
object: ["AnalyserNode"],
|
object: ["AnalyserNode"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getFloatTimeDomainData(array){
|
return function getFloatTimeDomainData(array){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments,
|
||||||
var {prefs, notify, window, original} = check;
|
fakeArrayCheckerCallback.bind(this, array, fakeFloat32Array)
|
||||||
notify("fakedAudioReadout");
|
);
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
fakeFloat32Array(array, window, prefs);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -212,13 +200,9 @@
|
|||||||
object: ["AnalyserNode"],
|
object: ["AnalyserNode"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getByteTimeDomainData(array){
|
return function getByteTimeDomainData(array){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments,
|
||||||
var {prefs, notify, window, original} = check;
|
fakeArrayCheckerCallback.bind(this, array, fakeUint8Array)
|
||||||
notify("fakedAudioReadout");
|
);
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
fakeUint8Array(array, window, prefs);
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -227,8 +211,8 @@
|
|||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getChannelData(channel){
|
return function getChannelData(channel){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
const ret = original.call(this, ...args);
|
||||||
if (!getChannelDataAlreadyFakedArrays.get(ret)){
|
if (!getChannelDataAlreadyFakedArrays.get(ret)){
|
||||||
notify("fakedAudioReadout");
|
notify("fakedAudioReadout");
|
||||||
fakeFloat32Array(ret, window, prefs);
|
fakeFloat32Array(ret, window, prefs);
|
||||||
@ -244,14 +228,14 @@
|
|||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function copyFromChannel(destination, channelNumber, startInChannel){
|
return function copyFromChannel(destination, channelNumber, startInChannel){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
var channelData = this.getChannelData(channelNumber);
|
const channelData = this.getChannelData(channelNumber);
|
||||||
if (!getChannelDataAlreadyFakedArrays.get(channelData)){
|
if (!getChannelDataAlreadyFakedArrays.get(channelData)){
|
||||||
notify("fakedAudioReadout");
|
notify("fakedAudioReadout");
|
||||||
fakeFloat32Array(channelData, window, prefs);
|
fakeFloat32Array(channelData, window, prefs);
|
||||||
getChannelDataAlreadyFakedArrays.set(channelData, true);
|
getChannelDataAlreadyFakedArrays.set(channelData, true);
|
||||||
}
|
}
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
const ret = original.call(this, ...args);
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -262,9 +246,9 @@
|
|||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getFrequencyResponse(frequencyArray, magResponseOutput, phaseResponseOutput){
|
return function getFrequencyResponse(frequencyArray, magResponseOutput, phaseResponseOutput){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
notify("fakedAudioReadout");
|
notify("fakedAudioReadout");
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
const ret = original.call(this, ...args);
|
||||||
fakeFloat32Array(magResponseOutput, window, prefs);
|
fakeFloat32Array(magResponseOutput, window, prefs);
|
||||||
fakeFloat32Array(phaseResponseOutput, window, prefs);
|
fakeFloat32Array(phaseResponseOutput, window, prefs);
|
||||||
return ret;
|
return ret;
|
||||||
@ -273,9 +257,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Object.keys(scope.changedFunctions).forEach(function(key){
|
|
||||||
scope.changedFunctions[key].type = "readout";
|
setFunctionProperties(scope.changedFunctions, {
|
||||||
scope.changedFunctions[key].getStatus = getStatus;
|
type: "readout",
|
||||||
scope.changedFunctions[key].api = "audio";
|
getStatus: getStatusByFlag("protectAudio"),
|
||||||
|
api: "audio"
|
||||||
});
|
});
|
||||||
}());
|
}());
|
@ -7,10 +7,11 @@
|
|||||||
const scope = ((typeof exports) !== "undefined")? exports: require.register("./modifiedCanvasAPI");
|
const scope = ((typeof exports) !== "undefined")? exports: require.register("./modifiedCanvasAPI");
|
||||||
const colorStatistics = require("./colorStatistics");
|
const colorStatistics = require("./colorStatistics");
|
||||||
const logging = require("./logging");
|
const logging = require("./logging");
|
||||||
const {copyCanvasToWebgl} = require("./webgl");
|
const extension = require("./extension");
|
||||||
const {getWrapped, checkerWrapper} = require("./modifiedAPIFunctions");
|
const webgl = require("./webgl");
|
||||||
|
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
||||||
|
|
||||||
var randomSupply = null;
|
let randomSupply = null;
|
||||||
|
|
||||||
function getContext(window, canvas){
|
function getContext(window, canvas){
|
||||||
return window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d") ||
|
return window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d") ||
|
||||||
@ -20,11 +21,11 @@
|
|||||||
window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl2");
|
window.HTMLCanvasElement.prototype.getContext.call(canvas, "experimental-webgl2");
|
||||||
}
|
}
|
||||||
function getImageData(window, context){
|
function getImageData(window, context){
|
||||||
var imageData;
|
let imageData;
|
||||||
var source;
|
let source;
|
||||||
if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){
|
if ((context.canvas.width || 0) * (context.canvas.height || 0) === 0){
|
||||||
imageData = new (getWrapped(window).ImageData)(0, 0);
|
imageData = new (extension.getWrapped(window).ImageData)(0, 0);
|
||||||
source = new (getWrapped(window).ImageData)(0, 0);
|
source = new (extension.getWrapped(window).ImageData)(0, 0);
|
||||||
}
|
}
|
||||||
else if (context instanceof window.CanvasRenderingContext2D){
|
else if (context instanceof window.CanvasRenderingContext2D){
|
||||||
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(
|
imageData = window.CanvasRenderingContext2D.prototype.getImageData.call(
|
||||||
@ -35,7 +36,7 @@
|
|||||||
source = imageData.data;
|
source = imageData.data;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
source = new Uint8Array(imageData.data.length);
|
||||||
(
|
(
|
||||||
context instanceof window.WebGLRenderingContext?
|
context instanceof window.WebGLRenderingContext?
|
||||||
@ -54,24 +55,25 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var canvasCache = Object.create(null);
|
const canvasCache = Object.create(null);
|
||||||
function getFakeCanvas(window, original, prefs){
|
function getFakeCanvas(window, original, prefs){
|
||||||
try {
|
try {
|
||||||
|
let originalDataURL;
|
||||||
if (prefs("useCanvasCache")){
|
if (prefs("useCanvasCache")){
|
||||||
var originalDataURL = original.toDataURL();
|
originalDataURL = original.toDataURL();
|
||||||
var cached = canvasCache[originalDataURL];
|
const cached = canvasCache[originalDataURL];
|
||||||
if (cached){
|
if (cached){
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// original may not be a canvas -> we must not leak an error
|
// original may not be a canvas -> we must not leak an error
|
||||||
var context = getContext(window, original);
|
let context = getContext(window, original);
|
||||||
var {imageData, source} = getImageData(window, context);
|
const {imageData, source} = getImageData(window, context);
|
||||||
var desc = imageData.data;
|
const desc = imageData.data;
|
||||||
var l = desc.length;
|
const l = desc.length;
|
||||||
|
|
||||||
var ignoredColors = {};
|
let ignoredColors = {};
|
||||||
var statistic;
|
let statistic;
|
||||||
if (prefs("ignoreFrequentColors")){
|
if (prefs("ignoreFrequentColors")){
|
||||||
statistic = colorStatistics.compute(source);
|
statistic = colorStatistics.compute(source);
|
||||||
ignoredColors = statistic.getMaxColors(prefs("ignoreFrequentColors"));
|
ignoredColors = statistic.getMaxColors(prefs("ignoreFrequentColors"));
|
||||||
@ -82,10 +84,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rng = randomSupply.getPixelRng(l, window, ignoredColors);
|
const rng = randomSupply.getPixelRng(l, window, ignoredColors);
|
||||||
var fakeAlphaChannel = prefs("fakeAlphaChannel");
|
const fakeAlphaChannel = prefs("fakeAlphaChannel");
|
||||||
for (var i = 0; i < l; i += 4){
|
for (let i = 0; i < l; i += 4){
|
||||||
var [r, g, b, a] = rng(
|
const [r, g, b, a] = rng(
|
||||||
source[i + 0],
|
source[i + 0],
|
||||||
source[i + 1],
|
source[i + 1],
|
||||||
source[i + 2],
|
source[i + 2],
|
||||||
@ -97,7 +99,7 @@
|
|||||||
desc[i + 2] = b;
|
desc[i + 2] = b;
|
||||||
desc[i + 3] = fakeAlphaChannel? a: source[i + 3];
|
desc[i + 3] = fakeAlphaChannel? a: source[i + 3];
|
||||||
}
|
}
|
||||||
var canvas = original.cloneNode(true);
|
const canvas = original.cloneNode(true);
|
||||||
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
|
context = window.HTMLCanvasElement.prototype.getContext.call(canvas, "2d");
|
||||||
context.putImageData(imageData, 0, 0);
|
context.putImageData(imageData, 0, 0);
|
||||||
if (prefs("useCanvasCache")){
|
if (prefs("useCanvasCache")){
|
||||||
@ -106,25 +108,25 @@
|
|||||||
}
|
}
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
logging.warning("Error while faking:", e);
|
logging.warning("Error while faking:", error);
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function randomMixImageData(window, imageData1, imageData2){
|
function randomMixImageData(window, imageData1, imageData2){
|
||||||
var data1 = imageData1.data;
|
const data1 = imageData1.data;
|
||||||
var data2 = imageData2.data;
|
const data2 = imageData2.data;
|
||||||
var l = data1.length;
|
const l = data1.length;
|
||||||
if (l === data2.length){
|
if (l === data2.length){
|
||||||
var rng = randomSupply.getPixelRng(l, window, {});
|
const rng = randomSupply.getPixelRng(l, window, {});
|
||||||
|
|
||||||
for (var i = 0; i < l; i += 4){
|
for (let i = 0; i < l; i += 4){
|
||||||
const signR = data1[i + 0] > data2[i + 0]? -1: 1;
|
const signR = data1[i + 0] > data2[i + 0]? -1: 1;
|
||||||
const signG = data1[i + 1] > data2[i + 1]? -1: 1;
|
const signG = data1[i + 1] > data2[i + 1]? -1: 1;
|
||||||
const signB = data1[i + 2] > data2[i + 2]? -1: 1;
|
const signB = data1[i + 2] > data2[i + 2]? -1: 1;
|
||||||
const signA = data1[i + 3] > data2[i + 3]? -1: 1;
|
const signA = data1[i + 3] > data2[i + 3]? -1: 1;
|
||||||
|
|
||||||
var [deltaR, deltaG, deltaB, deltaA] = rng(
|
const [deltaR, deltaG, deltaB, deltaA] = rng(
|
||||||
signR * (data2[i + 0] - data1[i + 0]),
|
signR * (data2[i + 0] - data1[i + 0]),
|
||||||
signG * (data2[i + 1] - data1[i + 1]),
|
signG * (data2[i + 1] - data1[i + 1]),
|
||||||
signB * (data2[i + 2] - data1[i + 2]),
|
signB * (data2[i + 2] - data1[i + 2]),
|
||||||
@ -142,9 +144,9 @@
|
|||||||
|
|
||||||
function canvasSizeShouldBeFaked(canvas, prefs){
|
function canvasSizeShouldBeFaked(canvas, prefs){
|
||||||
if (canvas){
|
if (canvas){
|
||||||
var size = canvas.height * canvas.width;
|
const size = canvas.height * canvas.width;
|
||||||
var maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY;
|
const maxSize = prefs("maxFakeSize") || Number.POSITIVE_INFINITY;
|
||||||
var minSize = prefs("minFakeSize") || 0;
|
const minSize = prefs("minFakeSize") || 0;
|
||||||
return size > minSize && size <= maxSize;
|
return size > minSize && size <= maxSize;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -180,8 +182,134 @@
|
|||||||
|
|
||||||
scope.setRandomSupply = function(supply){
|
scope.setRandomSupply = function(supply){
|
||||||
randomSupply = supply;
|
randomSupply = supply;
|
||||||
|
webgl.setRandomSupply(supply);
|
||||||
};
|
};
|
||||||
var canvasContextType = new WeakMap();
|
|
||||||
|
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 function getStatus(obj, status, prefs){
|
||||||
|
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
||||||
|
status = Object.create(status);
|
||||||
|
status.active = protectedPartChecker(protectedPart);
|
||||||
|
return status;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
return original.call(fakeCanvas, ...args);
|
||||||
|
}
|
||||||
|
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
|
// changed functions and their fakes
|
||||||
scope.changedFunctions = {
|
scope.changedFunctions = {
|
||||||
getContext: {
|
getContext: {
|
||||||
@ -209,125 +337,63 @@
|
|||||||
},
|
},
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function(context, contextAttributes){
|
return function getContext(context, contextAttributes){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {original} = check;
|
||||||
canvasContextType.set(this, context);
|
canvasContextType.set(this, context);
|
||||||
return original.apply(this, window.Array.from(args));
|
return original.call(this, ...args);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toDataURL: {
|
toDataURL: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout+"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
if (!status.active && protectedPartChecker("input")){
|
|
||||||
var contextType = canvasContextType.get(obj);
|
|
||||||
status.active = contextType !== "2d";
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function toDataURL(){
|
return function toDataURL(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||||
var {prefs, notify, window, original} = check;
|
|
||||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
|
||||||
var 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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toBlob: {
|
toBlob: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout+"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
if (!status.active && protectedPartChecker("input")){
|
|
||||||
var contextType = canvasContextType.get(obj);
|
|
||||||
status.active = contextType !== "2d";
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function toBlob(callback){
|
return function toBlob(callback){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
if (this instanceof toBlob){
|
||||||
var {prefs, notify, window, original} = check;
|
throw new extension.getWrapped(window).TypeError(
|
||||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
"HTMLCanvasElement.prototype.toBlob is not a constructor"
|
||||||
var fakeCanvas = getFakeCanvas(window, this, prefs);
|
);
|
||||||
if (fakeCanvas !== this){
|
}
|
||||||
notify("fakedReadout");
|
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||||
}
|
|
||||||
return original.apply(fakeCanvas, window.Array.from(args));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return original.apply(this, window.Array.from(args));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
exportOptions: {allowCallbacks: true}
|
exportOptions: {allowCallbacks: true}
|
||||||
},
|
},
|
||||||
mozGetAsFile: {
|
mozGetAsFile: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout+"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
if (!status.active && protectedPartChecker("input")){
|
|
||||||
var contextType = canvasContextType.get(obj);
|
|
||||||
status.active = contextType !== "2d";
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "HTMLCanvasElement",
|
object: "HTMLCanvasElement",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function mozGetAsFile(callback){
|
return function mozGetAsFile(callback){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, useFakeCanvasCallback);
|
||||||
var {prefs, notify, window, original} = check;
|
|
||||||
if (canvasSizeShouldBeFaked(this, prefs)){
|
|
||||||
var 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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
exportOptions: {allowCallbacks: true}
|
||||||
},
|
},
|
||||||
getImageData: {
|
getImageData: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getImageData(sx, sy, sw, sh){
|
return function getImageData(sx, sy, sw, sh){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
||||||
var fakeCanvas;
|
let fakeCanvas;
|
||||||
var context = this;
|
let context = this;
|
||||||
if (this && this.canvas) {
|
if (this && this.canvas) {
|
||||||
fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
|
fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
|
||||||
}
|
}
|
||||||
@ -338,10 +404,10 @@
|
|||||||
"2d"
|
"2d"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return original.apply(context, window.Array.from(args));
|
return original.call(context, ...args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return original.apply(this, window.Array.from(args));
|
return original.call(this, ...args);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -349,23 +415,21 @@
|
|||||||
},
|
},
|
||||||
isPointInPath: {
|
isPointInPath: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function isPointInPath(x, y){
|
return function isPointInPath(x, y){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
var rng = randomSupply.getValueRng(1, window);
|
const originalValue = original.call(this, ...args);
|
||||||
var originalValue = original.apply(this, window.Array.from(args));
|
|
||||||
if ((typeof originalValue) === "boolean"){
|
if ((typeof originalValue) === "boolean"){
|
||||||
notify("fakedReadout");
|
notify("fakedReadout");
|
||||||
var index = x + this.width * y;
|
return getIsPointValue({
|
||||||
return original.call(this, rng(x, index), rng(y, index), args[2]);
|
func: (x, y) => original.call(this, x, y, args[2]),
|
||||||
|
x, y,
|
||||||
|
index: x + this.canvas.width * y,
|
||||||
|
originalValue, window, prefs
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return originalValue;
|
return originalValue;
|
||||||
@ -376,32 +440,31 @@
|
|||||||
},
|
},
|
||||||
isPointInStroke: {
|
isPointInStroke: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("readout"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("readout");
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function isPointInStroke(x, y){
|
return function isPointInStroke(x, y){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
var rng = randomSupply.getValueRng(1, window);
|
const originalValue = original.call(this, ...args);
|
||||||
var originalValue = original.apply(this, window.Array.from(args));
|
|
||||||
if ((typeof originalValue) === "boolean"){
|
if ((typeof originalValue) === "boolean"){
|
||||||
notify("fakedReadout");
|
notify("fakedReadout");
|
||||||
|
let func;
|
||||||
if (x instanceof window.Path2D){
|
if (x instanceof window.Path2D){
|
||||||
let path = x;
|
let path = x;
|
||||||
x = y;
|
x = y;
|
||||||
y = args[2];
|
y = args[2];
|
||||||
let index = x + this.width * y;
|
func = (x, y) => original.call(this, path, x, y);
|
||||||
return original.call(this, path, rng(x, index), rng(y, index));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let index = x + this.width * y;
|
func = (x, y) => original.call(this, x, y);
|
||||||
return original.call(this, rng(x, index), rng(y, index));
|
|
||||||
}
|
}
|
||||||
|
return getIsPointValue({
|
||||||
|
func,
|
||||||
|
x, y,
|
||||||
|
index: x + this.canvas.width * y,
|
||||||
|
originalValue, window, prefs
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return originalValue;
|
return originalValue;
|
||||||
@ -412,106 +475,138 @@
|
|||||||
},
|
},
|
||||||
fillText: {
|
fillText: {
|
||||||
type: "input",
|
type: "input",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("input"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("input");
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function fillText(str, x, y){
|
return function fillText(str, x, y){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, mixOnInputCallback);
|
||||||
var {prefs, notify, window, original} = check;
|
|
||||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
|
||||||
notify("fakedInput");
|
|
||||||
var oldImageData;
|
|
||||||
try {
|
|
||||||
// "this" is not trustable - it may be not a context
|
|
||||||
oldImageData = getImageData(window, this).imageData;
|
|
||||||
}
|
|
||||||
catch (e){
|
|
||||||
// nothing to do here
|
|
||||||
}
|
|
||||||
// if "this" is not a correct context the next line will throw an error
|
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
var newImageData = getImageData(window, this).imageData;
|
|
||||||
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return original.apply(this, window.Array.from(args));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
strokeText: {
|
strokeText: {
|
||||||
type: "input",
|
type: "input",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus("input"),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker("input");
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: "CanvasRenderingContext2D",
|
object: "CanvasRenderingContext2D",
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function strokeText(str, x, y){
|
return function strokeText(str, x, y){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, mixOnInputCallback);
|
||||||
var {prefs, notify, window, original} = check;
|
|
||||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
|
||||||
notify("fakedInput");
|
|
||||||
var oldImageData;
|
|
||||||
try {
|
|
||||||
// "this" is not trustable - it may be not a context
|
|
||||||
oldImageData = getImageData(window, this).imageData;
|
|
||||||
}
|
|
||||||
catch (e){
|
|
||||||
// nothing to do here
|
|
||||||
}
|
|
||||||
// if "this" is not a correct context the next line will throw an error
|
|
||||||
var ret = original.apply(this, window.Array.from(args));
|
|
||||||
var newImageData = getImageData(window, this).imageData;
|
|
||||||
this.putImageData(randomMixImageData(window, oldImageData, newImageData), 0, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return original.apply(this, window.Array.from(args));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
readPixels: {
|
readPixels: {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: function(obj, status, prefs){
|
getStatus: createGetStatus(["readout", "input"]),
|
||||||
const protectedPartChecker = getProtectedPartChecker(prefs, status.url);
|
|
||||||
status = Object.create(status);
|
|
||||||
status.active = protectedPartChecker(["readout", "input"]);
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
|
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function readPixels(x, y, width, height, format, type, pixels){ // eslint-disable-line max-params
|
// eslint-disable-next-line max-params
|
||||||
|
return function readPixels(x, y, width, height, format, type, pixels){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
var {prefs, notify, window, original} = check;
|
const {prefs, notify, window, original} = check;
|
||||||
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
if (!this || canvasSizeShouldBeFaked(this.canvas, prefs)){
|
||||||
notify("fakedReadout");
|
notify("fakedReadout");
|
||||||
var fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
|
const fakeCanvas = getFakeCanvas(window, this.canvas, prefs);
|
||||||
var {context} = copyCanvasToWebgl(
|
const {context} = webgl.copyCanvasToWebgl(
|
||||||
window,
|
window,
|
||||||
fakeCanvas,
|
fakeCanvas,
|
||||||
this instanceof window.WebGLRenderingContext? "webgl": "webgl2"
|
this instanceof window.WebGLRenderingContext? "webgl": "webgl2"
|
||||||
);
|
);
|
||||||
return original.apply(context, window.Array.from(args));
|
return original.call(context, ...args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return original.apply(this, window.Array.from(args));
|
return original.call(this, ...args);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
getParameter: {
|
||||||
|
type: "readout",
|
||||||
|
getStatus: createGetStatus(["readout", "input"]),
|
||||||
|
object: ["WebGLRenderingContext", "WebGL2RenderingContext"],
|
||||||
|
fakeGenerator: function(checker){
|
||||||
|
webgl.initializeParameterDefinitions();
|
||||||
|
return function getParameter(pname){
|
||||||
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return originalValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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){
|
Object.keys(scope.changedFunctions).forEach(function(key){
|
||||||
scope.changedFunctions[key].api = "canvas";
|
scope.changedFunctions[key].api = "canvas";
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
scope = require.register("./modifiedDOMRectAPI", {});
|
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");
|
const {byteArrayToString: hash} = require("./hash");
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +31,7 @@
|
|||||||
|
|
||||||
const registeredRects = new WeakMap();
|
const registeredRects = new WeakMap();
|
||||||
function registerDOMRect(domRect, notify, window, prefs){
|
function registerDOMRect(domRect, notify, window, prefs){
|
||||||
registeredRects.set(getWrapped(domRect), {
|
registeredRects.set(extension.getWrapped(domRect), {
|
||||||
notify: function(){
|
notify: function(){
|
||||||
let done = false;
|
let done = false;
|
||||||
return function(message){
|
return function(message){
|
||||||
@ -45,47 +46,104 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getDOMRectRegistration(domRect){
|
function getDOMRectRegistration(domRect){
|
||||||
return registeredRects.get(getWrapped(domRect));
|
return registeredRects.get(extension.getWrapped(domRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = {};
|
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){
|
function getFakeDomRect(window, domRect, prefs, notify){
|
||||||
const hash = getHash(domRect);
|
const hash = getHash(domRect);
|
||||||
let cached = cache[hash];
|
let cached = cache[hash];
|
||||||
if (!cached){
|
if (!cached){
|
||||||
notify("fakedDOMRectReadout");
|
notify("fakedDOMRectReadout");
|
||||||
const rng = randomSupply.getRng(4, window);
|
const rng = randomSupply.getRng(4, window);
|
||||||
const getFakeValue = function getFakeValue(value, i){
|
const env = {window, prefs, rng};
|
||||||
const valueHash = getValueHash(value);
|
cached = new (domRect instanceof window.SVGRect? window.DOMRectReadOnly: domRect.constructor)(
|
||||||
const cache = valueCache[i];
|
getFakeValue(domRect.x, 0, env),
|
||||||
let cachedValue = cache[valueHash];
|
getFakeValue(domRect.y, 1, env),
|
||||||
if (typeof cachedValue === "number"){
|
getFakeValue(domRect.width, 2, env),
|
||||||
return cachedValue;
|
getFakeValue(domRect.height, 3, env)
|
||||||
}
|
|
||||||
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)
|
|
||||||
);
|
);
|
||||||
cache[hash] = cached;
|
cache[hash] = cached;
|
||||||
cache[getHash(cached)] = cached;
|
cache[getHash(cached)] = cached;
|
||||||
}
|
}
|
||||||
return 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 = {
|
scope.changedFunctions = {
|
||||||
getClientRects: {
|
getClientRects: {
|
||||||
@ -94,7 +152,7 @@
|
|||||||
return function getClientRects(){
|
return function getClientRects(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = 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){
|
for (let i = 0; i < ret.length; i += 1){
|
||||||
registerDOMRect(ret[i], notify, window, prefs);
|
registerDOMRect(ret[i], notify, window, prefs);
|
||||||
}
|
}
|
||||||
@ -107,52 +165,74 @@
|
|||||||
object: ["Range", "Element"],
|
object: ["Range", "Element"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getBoundingClientRect(){
|
return function getBoundingClientRect(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getBounds: {
|
getBoxQuads: {
|
||||||
object: ["DOMQuad"],
|
object: ["Document", "Element", "Text", "CSSPseudoElement"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getBounds(){
|
return function getBoxQuads(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = 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);
|
||||||
registerDOMRect(ret, notify, window, prefs);
|
for (let i = 0; i < ret.length; i += 1){
|
||||||
|
ret[i] = getFakeDOMQuad(window, ret[i], prefs, notify);
|
||||||
|
}
|
||||||
return ret;
|
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: {
|
getBBox: {
|
||||||
object: ["SVGGraphicsElement"],
|
object: ["SVGGraphicsElement"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getBBox(){
|
return function getBBox(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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;
|
|
||||||
});
|
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: {
|
getExtentOfChar: {
|
||||||
object: ["SVGTextContentElement"],
|
object: ["SVGTextContentElement"],
|
||||||
fakeGenerator: function(checker){
|
fakeGenerator: function(checker){
|
||||||
return function getBBox(){
|
return function getExtentOfChar(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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;
|
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.DOMRect && window.DOMRect.prototype;},
|
||||||
|
function(window){return window.SVGRect && window.SVGRect.prototype;},
|
||||||
function(window){return window.DOMRectReadOnly && window.DOMRectReadOnly.prototype;}
|
function(window){return window.DOMRectReadOnly && window.DOMRectReadOnly.prototype;}
|
||||||
],
|
],
|
||||||
name: property,
|
name: property,
|
||||||
getterGenerator: function(){
|
getterGenerator: function(){
|
||||||
const temp = eval(`({
|
const temp = {
|
||||||
get ${property}(){
|
get [property](){
|
||||||
const registration = getDOMRectRegistration(this);
|
const registration = getDOMRectRegistration(this);
|
||||||
if (registration){
|
if (registration){
|
||||||
return getFakeDomRect(
|
return getFakeDomRect(
|
||||||
@ -179,24 +260,24 @@
|
|||||||
this,
|
this,
|
||||||
registration.prefs,
|
registration.prefs,
|
||||||
registration.notify
|
registration.notify
|
||||||
).${property};
|
)[property];
|
||||||
}
|
}
|
||||||
return this.${property};
|
return this[property];
|
||||||
}
|
}
|
||||||
})`);
|
};
|
||||||
return Object.getOwnPropertyDescriptor(temp, property).get;
|
return Object.getOwnPropertyDescriptor(temp, property).get;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!readonly){
|
if (!readonly){
|
||||||
changedGetter.setterGenerator = function(window, original, prefs){
|
changedGetter.setterGenerator = function(window, original, prefs){
|
||||||
const temp = eval(`({
|
const temp = {
|
||||||
set ${property}(newValue){
|
set [property](newValue){
|
||||||
const registration = getDOMRectRegistration(this);
|
const registration = getDOMRectRegistration(this);
|
||||||
if (registration){
|
if (registration){
|
||||||
const fakeDomRect = getFakeDomRect(window, this, prefs, registration.notify);
|
const fakeDomRect = getFakeDomRect(window, this, prefs, registration.notify);
|
||||||
registeredRects.delete(getWrapped(this));
|
registeredRects.delete(extension.getWrapped(this));
|
||||||
["x", "y", "width", "height"].forEach((prop) => {
|
["x", "y", "width", "height"].forEach((prop) => {
|
||||||
if (prop === "${property}"){
|
if (prop === property){
|
||||||
this[prop] = newValue;
|
this[prop] = newValue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -205,10 +286,10 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
original.apply(this, window.Array.from(arguments));
|
original.call(this, ...arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})`);
|
};
|
||||||
return Object.getOwnPropertyDescriptor(temp, property).set;
|
return Object.getOwnPropertyDescriptor(temp, property).set;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -234,14 +315,7 @@
|
|||||||
getterGenerator: function(checker){
|
getterGenerator: function(checker){
|
||||||
const temp = {
|
const temp = {
|
||||||
get intersectionRect(){
|
get intersectionRect(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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 Object.getOwnPropertyDescriptor(temp, "intersectionRect").get;
|
return Object.getOwnPropertyDescriptor(temp, "intersectionRect").get;
|
||||||
@ -257,14 +331,7 @@
|
|||||||
getterGenerator: function(checker){
|
getterGenerator: function(checker){
|
||||||
const temp = {
|
const temp = {
|
||||||
get boundingClientRect(){
|
get boundingClientRect(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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 Object.getOwnPropertyDescriptor(temp, "boundingClientRect").get;
|
return Object.getOwnPropertyDescriptor(temp, "boundingClientRect").get;
|
||||||
@ -280,14 +347,7 @@
|
|||||||
getterGenerator: function(checker){
|
getterGenerator: function(checker){
|
||||||
const temp = {
|
const temp = {
|
||||||
get rootBounds(){
|
get rootBounds(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, registerCallback);
|
||||||
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 Object.getOwnPropertyDescriptor(temp, "rootBounds").get;
|
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, {
|
setProperties(scope.changedFunctions, scope.changedGetters, {
|
||||||
type: "readout",
|
type: "readout",
|
||||||
getStatus: getStatus,
|
getStatus: getStatusByFlag("protectDOMRect"),
|
||||||
api: "domRect"
|
api: "domRect"
|
||||||
});
|
});
|
||||||
}());
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@
|
|||||||
scope = require.register("./modifiedHistoryAPI", {});
|
scope = require.register("./modifiedHistoryAPI", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
const {checkerWrapper, setGetterProperties} = require("./modifiedAPIFunctions");
|
||||||
|
|
||||||
scope.changedGetters = [
|
scope.changedGetters = [
|
||||||
{
|
{
|
||||||
@ -23,7 +23,7 @@
|
|||||||
get length(){
|
get length(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = 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);
|
const threshold = prefs("historyLengthThreshold", window.location);
|
||||||
if (originalLength > threshold){
|
if (originalLength > threshold){
|
||||||
notify("fakedHistoryReadout");
|
notify("fakedHistoryReadout");
|
||||||
@ -47,9 +47,9 @@
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.changedGetters.forEach(function(changedGetter){
|
setGetterProperties(scope.changedGetters, {
|
||||||
changedGetter.type = "readout";
|
type: "readout",
|
||||||
changedGetter.getStatus = getStatus;
|
getStatus: getStatus,
|
||||||
changedGetter.api = "history";
|
api: "history"
|
||||||
});
|
});
|
||||||
}());
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -12,41 +12,85 @@
|
|||||||
scope = require.register("./modifiedNavigatorAPI", {});
|
scope = require.register("./modifiedNavigatorAPI", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
const {checkerWrapper, setProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
const extension = require("./extension");
|
||||||
const navigator = require("./navigator");
|
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){
|
scope.changedGetters = navigator.allProperties.map(function(property){
|
||||||
return {
|
return {
|
||||||
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
|
objectGetters: [function(window){return window.Navigator && window.Navigator.prototype;}],
|
||||||
name: property,
|
name: property,
|
||||||
getterGenerator: function(checker){
|
getterGenerator: function(checker){
|
||||||
const temp = eval(`({
|
const temp = {
|
||||||
get ${property}(){
|
get [property](){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = check;
|
const {notify, original} = check;
|
||||||
const originalValue = original.apply(this, window.Array.from(args));
|
const originalValue = original.call(this, ...args);
|
||||||
const returnValue = navigator.getNavigatorValue("${property}");
|
const returnValue = navigator.getNavigatorValue(property, getCookieStoreId);
|
||||||
if (originalValue !== returnValue){
|
if (originalValue !== returnValue){
|
||||||
notify("fakedNavigatorReadout");
|
notify("fakedNavigatorReadout");
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})`);
|
};
|
||||||
return Object.getOwnPropertyDescriptor(temp, property).get;
|
return Object.getOwnPropertyDescriptor(temp, property).get;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function getStatus(obj, status, prefs){
|
scope.changedFunctions = {
|
||||||
status = Object.create(status);
|
estimate: {
|
||||||
status.active = prefs("protectNavigator", status.url);
|
objectGetters: [function(window){return window.StorageManager && window.StorageManager.prototype;}],
|
||||||
return status;
|
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){
|
setProperties(scope.changedFunctions, scope.changedGetters, {
|
||||||
changedGetter.type = "readout";
|
type: "readout",
|
||||||
changedGetter.getStatus = getStatus;
|
getStatus: getStatusByFlag("protectNavigator"),
|
||||||
changedGetter.api = "navigator";
|
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"
|
||||||
|
});
|
||||||
|
}());
|
291
lib/modifiedScreenAPI.js
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
/* 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("./modifiedScreenAPI", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
|
||||||
|
const physical = {
|
||||||
|
width: Math.round(window.screen.width * window.devicePixelRatio),
|
||||||
|
height: Math.round(window.screen.height * window.devicePixelRatio)
|
||||||
|
};
|
||||||
|
if (!window.matchMedia(`(device-width: ${physical.width / window.devicePixelRatio}px`).matches){
|
||||||
|
let minWidth = Math.ceil((window.screen.width - 0.5) * window.devicePixelRatio);
|
||||||
|
let maxWidth = Math.floor((window.screen.width + 0.5) * window.devicePixelRatio);
|
||||||
|
for (let width = minWidth; width <= maxWidth; width += 1){
|
||||||
|
if (window.matchMedia(`(device-width: ${width / window.devicePixelRatio}px`).matches){
|
||||||
|
physical.width = width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.matchMedia(`(device-height: ${physical.height / window.devicePixelRatio}px`).matches){
|
||||||
|
let minHeight = Math.ceil((window.screen.height - 0.5) * window.devicePixelRatio);
|
||||||
|
let maxHeight = Math.floor((window.screen.height + 0.5) * window.devicePixelRatio);
|
||||||
|
for (let height = minHeight; height <= maxHeight; height += 1){
|
||||||
|
if (window.matchMedia(`(device-height: ${height / window.devicePixelRatio}px`).matches){
|
||||||
|
physical.height = height;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolutions = {
|
||||||
|
portrait: [
|
||||||
|
{height: 1366, width: 768},
|
||||||
|
{height: 1440, width: 900},
|
||||||
|
{height: 1600, width: 900},
|
||||||
|
{height: 1920, width: 1080},
|
||||||
|
{height: 2560, width: 1440},
|
||||||
|
{height: 4096, width: 2160},
|
||||||
|
{height: 8192, width: 6144},
|
||||||
|
],
|
||||||
|
landscape: [
|
||||||
|
{width: 1366, height: 768},
|
||||||
|
{width: 1440, height: 900},
|
||||||
|
{width: 1600, height: 900},
|
||||||
|
{width: 1920, height: 1080},
|
||||||
|
{width: 2560, height: 1440},
|
||||||
|
{width: 4096, height: 2160},
|
||||||
|
{width: 8192, height: 6144},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
function getScreenDimensions(prefs, window){
|
||||||
|
const screenSize = prefs("screenSize", window.location);
|
||||||
|
if (screenSize.match(/\s*\d+\s*x\s*\d+\s*$/)){
|
||||||
|
const [width, height] = screenSize.split("x").map(function(value){
|
||||||
|
return Math.round(parseFloat(value.trim()));
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
width: width / window.devicePixelRatio,
|
||||||
|
height: height / window.devicePixelRatio
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!prefs("fakeMinimalScreenSize", window.location)){
|
||||||
|
return window.screen;
|
||||||
|
}
|
||||||
|
const isLandscape = window.screen.width > window.screen.height;
|
||||||
|
// subtract 0.5 to adjust for potential rounding errors
|
||||||
|
const innerWidth = (window.innerWidth - 0.5) * window.devicePixelRatio;
|
||||||
|
const innerHeight = (window.innerHeight - 0.5) * window.devicePixelRatio;
|
||||||
|
for (let resolution of resolutions[isLandscape? "landscape": "portrait"]){
|
||||||
|
if (resolution.width >= innerWidth && resolution.height >= innerHeight){
|
||||||
|
return {
|
||||||
|
width: resolution.width / window.devicePixelRatio,
|
||||||
|
height: resolution.height / window.devicePixelRatio
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return window.screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFaker(dimension){
|
||||||
|
return function fake(args, check){
|
||||||
|
const {prefs, notify, window, original} = check;
|
||||||
|
const originalValue = original.call(this, ...args);
|
||||||
|
const returnValue = (typeof dimension) === "function"?
|
||||||
|
dimension(window):
|
||||||
|
dimension?
|
||||||
|
Math.round(getScreenDimensions(prefs, window)[dimension]):
|
||||||
|
0;
|
||||||
|
if (originalValue !== returnValue){
|
||||||
|
notify("fakedScreenReadout");
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.changedGetters = [
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "width",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get width(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker("width"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "width").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "height",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get height(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker("height"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "height").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "availWidth",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get availWidth(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker("width"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "availWidth").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "availHeight",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get availHeight(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker("height"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "availHeight").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "availLeft",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get availLeft(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker(0));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "availLeft").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window.Screen && window.Screen.prototype;}],
|
||||||
|
name: "availTop",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get availTop(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker(0));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "availTop").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window;}],
|
||||||
|
name: "outerWidth",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get outerWidth(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker(window => window.top.innerWidth));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "outerWidth").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectGetters: [function(window){return window;}],
|
||||||
|
name: "outerHeight",
|
||||||
|
getterGenerator: function(checker){
|
||||||
|
const temp = {
|
||||||
|
get outerHeight(){
|
||||||
|
return checkerWrapper(checker, this, arguments, getFaker(window => window.top.innerHeight));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "outerHeight").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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.call(this, ...args);
|
||||||
|
const screenSize = prefs("screenSize", window.location);
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
screenSize.match(/\s*\d+\s*x\s*\d+\s*$/) ||
|
||||||
|
prefs("fakeMinimalScreenSize", window.location)
|
||||||
|
) &&
|
||||||
|
this.media.match(/device-(width|height)/)
|
||||||
|
){
|
||||||
|
const originalMedia = this.media;
|
||||||
|
const alteredMedia = getAlteredMedia(originalMedia, prefs, window);
|
||||||
|
if (alteredMedia !== originalMedia){
|
||||||
|
const alteredQuery = window.matchMedia(alteredMedia);
|
||||||
|
const fakedValue = original.call(alteredQuery);
|
||||||
|
if (originalValue !== fakedValue){
|
||||||
|
notify("fakedScreenReadout");
|
||||||
|
}
|
||||||
|
return fakedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return originalValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Object.getOwnPropertyDescriptor(temp, "matches").get;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
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"
|
||||||
|
});
|
||||||
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@
|
|||||||
scope = require.register("./modifiedWindowAPI", {});
|
scope = require.register("./modifiedWindowAPI", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {checkerWrapper} = require("./modifiedAPIFunctions");
|
const {checkerWrapper, setGetterProperties, getStatusByFlag} = require("./modifiedAPIFunctions");
|
||||||
|
|
||||||
const windowNames = new WeakMap();
|
const windowNames = new WeakMap();
|
||||||
scope.changedGetters = [
|
scope.changedGetters = [
|
||||||
@ -23,11 +23,8 @@
|
|||||||
const temp = {
|
const temp = {
|
||||||
get opener(){
|
get opener(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = check;
|
const {notify, original} = check;
|
||||||
if (!prefs("protectWindow", window.location)){
|
const originalOpener = original.call(this, ...args);
|
||||||
return original.apply(this, window.Array.from(args));
|
|
||||||
}
|
|
||||||
const originalOpener = original.apply(this, window.Array.from(args));
|
|
||||||
if (originalOpener !== null){
|
if (originalOpener !== null){
|
||||||
notify("fakedWindowReadout");
|
notify("fakedWindowReadout");
|
||||||
}
|
}
|
||||||
@ -36,6 +33,12 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Object.getOwnPropertyDescriptor(temp, "opener").get;
|
return Object.getOwnPropertyDescriptor(temp, "opener").get;
|
||||||
|
},
|
||||||
|
valueGenerator: function({original, notify}){
|
||||||
|
if (original !== null){
|
||||||
|
notify("fakedWindowReadout");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -45,12 +48,15 @@
|
|||||||
const temp = {
|
const temp = {
|
||||||
get name(){
|
get name(){
|
||||||
return checkerWrapper(checker, this, arguments, function(args, check){
|
return checkerWrapper(checker, this, arguments, function(args, check){
|
||||||
const {prefs, notify, window, original} = check;
|
const {notify, original, prefs} = check;
|
||||||
if (!prefs("protectWindow", window.location)){
|
const originalName = original.call(this, ...args);
|
||||||
return original.apply(this, window.Array.from(args));
|
if (
|
||||||
|
this !== this.top &&
|
||||||
|
prefs("allowWindowNameInFrames", this.location)
|
||||||
|
){
|
||||||
|
return originalName;
|
||||||
}
|
}
|
||||||
const originalName = original.apply(this, window.Array.from(args));
|
const returnedName = windowNames.get(this) || "";
|
||||||
const returnedName = windowNames.get(window) || "";
|
|
||||||
if (originalName !== returnedName){
|
if (originalName !== returnedName){
|
||||||
notify("fakedWindowReadout");
|
notify("fakedWindowReadout");
|
||||||
}
|
}
|
||||||
@ -63,8 +69,8 @@
|
|||||||
setterGenerator: function(window, original){
|
setterGenerator: function(window, original){
|
||||||
const temp = {
|
const temp = {
|
||||||
set name(name){
|
set name(name){
|
||||||
original.apply(this, window.Array.from(arguments));
|
original.call(this, ...arguments);
|
||||||
windowNames.set(window, name);
|
windowNames.set(this, name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Object.getOwnPropertyDescriptor(temp, "name").set;
|
return Object.getOwnPropertyDescriptor(temp, "name").set;
|
||||||
@ -72,15 +78,9 @@
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
function getStatus(obj, status, prefs){
|
setGetterProperties(scope.changedGetters, {
|
||||||
status = Object.create(status);
|
type: "readout",
|
||||||
status.active = prefs("protectWindow", status.url);
|
getStatus: getStatusByFlag("protectWindow"),
|
||||||
return status;
|
api: "window"
|
||||||
}
|
|
||||||
|
|
||||||
scope.changedGetters.forEach(function(changedGetter){
|
|
||||||
changedGetter.type = "readout";
|
|
||||||
changedGetter.getStatus = getStatus;
|
|
||||||
changedGetter.api = "window";
|
|
||||||
});
|
});
|
||||||
}());
|
}());
|
108
lib/navigator.js
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -26,6 +26,7 @@
|
|||||||
original[property] = window.navigator[property];
|
original[property] = window.navigator[property];
|
||||||
});
|
});
|
||||||
original["real Firefox version"] = window.navigator.userAgent.replace(/^.+Firefox\//, "");
|
original["real Firefox version"] = window.navigator.userAgent.replace(/^.+Firefox\//, "");
|
||||||
|
original["real Firefox version - rv"] = window.navigator.userAgent.replace(/^.+; rv:([\d.]+).*$/, "$1");
|
||||||
|
|
||||||
let changedValues = {};
|
let changedValues = {};
|
||||||
|
|
||||||
@ -36,35 +37,63 @@
|
|||||||
changedValues = newValue;
|
changedValues = newValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getValue = function(){
|
||||||
function getValue(name, stack = []){
|
function getChangedValues(getCookieStoreId){
|
||||||
if (stack.indexOf(name) !== -1){
|
if (changedValues.contextualIdentities){
|
||||||
return "[ERROR: loop in property definition]";
|
const cookieStoreId = getCookieStoreId();
|
||||||
}
|
if (
|
||||||
stack.push(name);
|
cookieStoreId !== "" &&
|
||||||
|
cookieStoreId !== "firefox-default" &&
|
||||||
switch (name){
|
changedValues.contextualIdentities[cookieStoreId]
|
||||||
case "original value":
|
){
|
||||||
return original[stack[stack.length - 2]];
|
return changedValues.contextualIdentities[cookieStoreId];
|
||||||
case "random":
|
|
||||||
return String.fromCharCode(Math.floor(65 + 85 * Math.random()));
|
|
||||||
default:
|
|
||||||
if (changedValues.hasOwnProperty(name)){
|
|
||||||
return parseString(changedValues[name], stack.slice());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return original[name];
|
return changedValues;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return changedValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
function parseString(string, stack){
|
return function getValue(name, getCookieStoreId){
|
||||||
return string.replace(/{([a-z[\]_. -]*)}/ig, function(m, name){
|
const changedValues = getChangedValues(getCookieStoreId);
|
||||||
return getValue(name, stack.slice());
|
|
||||||
});
|
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){
|
scope.getNavigatorValue = function getNavigatorValue(name, getCookieStoreId){
|
||||||
return getValue(name);
|
return getValue(name, getCookieStoreId);
|
||||||
};
|
};
|
||||||
|
|
||||||
function changeHTTPHeader(details){
|
function changeHTTPHeader(details){
|
||||||
@ -73,13 +102,15 @@
|
|||||||
settings.get("protectNavigator", url) &&
|
settings.get("protectNavigator", url) &&
|
||||||
check.check({url}).mode !== "allow" &&
|
check.check({url}).mode !== "allow" &&
|
||||||
(
|
(
|
||||||
!settings.protectedAPIFeatures.hasOwnProperty("userAgent") ||
|
!settings.protectedAPIFeatures.hasOwnProperty("userAgent @ navigator") ||
|
||||||
settings.protectedAPIFeatures.userAgent
|
settings.protectedAPIFeatures["userAgent @ navigator"]
|
||||||
)
|
)
|
||||||
){
|
){
|
||||||
for (var header of details.requestHeaders){
|
for (let header of details.requestHeaders){
|
||||||
if (header.name.toLowerCase() === "user-agent"){
|
if (header.name.toLowerCase() === "user-agent"){
|
||||||
header.value = getValue("userAgent");
|
header.value = getValue("userAgent", function(){
|
||||||
|
return details.cookieStoreId;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,5 +146,24 @@
|
|||||||
scope.unregisterHeaderChange();
|
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"
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}());
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -163,13 +163,12 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on("showNotifications", function({newValue}){
|
settings.on("showNotifications", async function({newValue}){
|
||||||
if (!newValue){
|
if (!newValue){
|
||||||
logging.message("notifications were disabled -> hide all page actions");
|
logging.message("notifications were disabled -> hide all page actions");
|
||||||
browser.tabs.query({}).then(function(tabs){
|
const tabs = await browser.tabs.query({});
|
||||||
tabs.forEach(function(tab){
|
tabs.forEach(function(tab){
|
||||||
browser.pageAction.hide(tab.id);
|
browser.pageAction.hide(tab.id);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -177,16 +176,15 @@
|
|||||||
browser.tabs.onRemoved.addListener(function(tabId){
|
browser.tabs.onRemoved.addListener(function(tabId){
|
||||||
tabsData.delete(tabId);
|
tabsData.delete(tabId);
|
||||||
});
|
});
|
||||||
settings.on("displayBadge", function({newValue}){
|
settings.on("displayBadge", async function({newValue}){
|
||||||
if (!newValue){
|
if (!newValue){
|
||||||
logging.message("badge was disabled -> hide all badges");
|
logging.message("badge was disabled -> hide all badges");
|
||||||
if (browser.browserAction.setBadgeText){
|
if (browser.browserAction.setBadgeText){
|
||||||
browser.tabs.query({}).then(function(tabs){
|
const tabs = await browser.tabs.query({});
|
||||||
tabs.forEach(function(tab){
|
tabs.forEach(function(tab){
|
||||||
browser.browserAction.setBadgeText({
|
browser.browserAction.setBadgeText({
|
||||||
tabId: tab.id,
|
tabId: tab.id,
|
||||||
text: ""
|
text: ""
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
scope.persistentRnd = Object.create(null);
|
scope.persistentRnd = Object.create(null);
|
||||||
scope.persistentIncognitoRnd = Object.create(null);
|
scope.persistentIncognitoRnd = Object.create(null);
|
||||||
|
let clearTimeout;
|
||||||
scope.init = function init(){
|
scope.init = function init(){
|
||||||
logging.message("initializing persistent rng storage");
|
logging.message("initializing persistent rng storage");
|
||||||
|
|
||||||
@ -26,8 +27,8 @@
|
|||||||
if (settings.storePersistentRnd){
|
if (settings.storePersistentRnd){
|
||||||
try {
|
try {
|
||||||
let storedData = JSON.parse(settings.persistentRndStorage);
|
let storedData = JSON.parse(settings.persistentRndStorage);
|
||||||
for (var domain in storedData){
|
for (let domain in storedData){
|
||||||
var value = storedData[domain];
|
const value = storedData[domain];
|
||||||
if (
|
if (
|
||||||
Array.isArray(value) &&
|
Array.isArray(value) &&
|
||||||
value.length === 128 &&
|
value.length === 128 &&
|
||||||
@ -39,7 +40,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
// JSON is not valid -> ignore it
|
// JSON is not valid -> ignore it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +75,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getInterval = function(){
|
const getInterval = function(){
|
||||||
var units = {
|
const units = {
|
||||||
seconds: 1000,
|
seconds: 1000,
|
||||||
minutes: 60 * 1000,
|
minutes: 60 * 1000,
|
||||||
hours: 60 * 60 * 1000,
|
hours: 60 * 60 * 1000,
|
||||||
@ -88,25 +89,14 @@
|
|||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
browser.windows.onRemoved.addListener(function(){
|
|
||||||
browser.windows.getAll().then(function(windows){
|
|
||||||
if (windows.every(function(window){
|
|
||||||
return !window.incognito;
|
|
||||||
})){
|
|
||||||
clearIncognito();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let clearTimeout;
|
|
||||||
function registerTimeout(){
|
function registerTimeout(){
|
||||||
var interval = getInterval();
|
const interval = getInterval();
|
||||||
if (interval > 0){
|
if (interval > 0){
|
||||||
var 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");
|
logging.message("registering persistent rng data clearing timeout. Clearing in ", timeout, "ms");
|
||||||
if (timeout > 1073741824){
|
if (timeout > 1073741824){
|
||||||
// window.setTimeout can only handle delays up to 32 bit.
|
// window.setTimeout can only handle delays up to 32 bit.
|
||||||
// Therefore we repeat the registering afert 2^30 = 1073741824 seconds
|
// Therefore we repeat the registering after 2^30 = 1073741824 seconds
|
||||||
clearTimeout = window.setTimeout(registerTimeout, 1073741824);
|
clearTimeout = window.setTimeout(registerTimeout, 1073741824);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -114,25 +104,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function broadcast(data){
|
async function broadcast(data){
|
||||||
browser.tabs.query({}).then(function(tabs){
|
const tabs = await browser.tabs.query({});
|
||||||
tabs.forEach(function(tab){
|
tabs.forEach(function(tab){
|
||||||
browser.tabs.sendMessage(tab.id, data);
|
browser.tabs.sendMessage(tab.id, data);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function clearIncognito(){
|
function clearIncognito(){
|
||||||
scope.persistentIncognitoRnd = Object.create(null);
|
scope.persistentIncognitoRnd = Object.create(null);
|
||||||
settings.persistentIncognitoRndStorage = JSON.stringify(scope.persistentIncognitoRnd);
|
settings.persistentIncognitoRndStorage = JSON.stringify(scope.persistentIncognitoRnd);
|
||||||
}
|
}
|
||||||
function clear(){
|
function clear(force = false){
|
||||||
logging.verbose("domain rnd cleared");
|
logging.verbose("domain rnd cleared");
|
||||||
scope.persistentRnd = Object.create(null);
|
scope.persistentRnd = Object.create(null);
|
||||||
settings.persistentRndStorage = JSON.stringify(scope.persistentRnd);
|
settings.persistentRndStorage = JSON.stringify(scope.persistentRnd);
|
||||||
settings.lastPersistentRndClearing = Date.now();
|
settings.lastPersistentRndClearing = Date.now();
|
||||||
clearIncognito();
|
clearIncognito();
|
||||||
registerTimeout();
|
registerTimeout();
|
||||||
broadcast({"canvasBlocker-clear-domain-rnd": true});
|
broadcast({"canvasBlocker-clear-domain-rnd": force? "force": true});
|
||||||
}
|
}
|
||||||
function setDomainData(domain, incognito, rnd){
|
function setDomainData(domain, incognito, rnd){
|
||||||
logging.verbose("got new domain rnd for ", domain, " (incognito:", incognito, "):", rnd);
|
logging.verbose("got new domain rnd for ", domain, " (incognito:", incognito, "):", rnd);
|
||||||
@ -175,4 +164,18 @@
|
|||||||
scope.setDomainData = setDomainData;
|
scope.setDomainData = setDomainData;
|
||||||
scope.clearDomainData = clearDomainData;
|
scope.clearDomainData = clearDomainData;
|
||||||
scope.clearContainerData = clearContainerData;
|
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);
|
||||||
|
}
|
||||||
}());
|
}());
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -15,7 +15,6 @@
|
|||||||
const rngTemplate = {
|
const rngTemplate = {
|
||||||
getBitRng: function(length, window){
|
getBitRng: function(length, window){
|
||||||
const rng = this.getRng(Math.ceil(length / 32), window);
|
const rng = this.getRng(Math.ceil(length / 32), window);
|
||||||
let bitIndex = 32;
|
|
||||||
let rnd = 0;
|
let rnd = 0;
|
||||||
let mask = 0xffffffff * 2;
|
let mask = 0xffffffff * 2;
|
||||||
return function(value, i){
|
return function(value, i){
|
||||||
@ -38,20 +37,21 @@
|
|||||||
getValueRng: function(length, window){
|
getValueRng: function(length, window){
|
||||||
const rng = this.getBitRng(length, window);
|
const rng = this.getBitRng(length, window);
|
||||||
return function(value, i){
|
return function(value, i){
|
||||||
var rnd = rng(value, i);
|
const rnd = rng(value, i);
|
||||||
|
|
||||||
// XOR the last bit to alter it... or not
|
// XOR the last bit to alter it... or not
|
||||||
return value ^ (rnd & 0x01);
|
return value ^ (rnd & 0x01);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getPixelRng: function(length, window, ignoredColors){
|
getPixelRng: function(length, window, ignoredColors){
|
||||||
var rng = this.getValueRng(length, window);
|
const rng = this.getValueRng(length, window);
|
||||||
return function(r, g, b, a, i){ // eslint-disable-line max-params
|
// eslint-disable-next-line max-params
|
||||||
var index = String.fromCharCode(r, g, b, a);
|
return function(r, g, b, a, i){
|
||||||
|
const index = String.fromCharCode(r, g, b, a);
|
||||||
if (ignoredColors[index]){
|
if (ignoredColors[index]){
|
||||||
return [r, g, b, a];
|
return [r, g, b, a];
|
||||||
}
|
}
|
||||||
var baseIndex = i * 4;
|
const baseIndex = i * 4;
|
||||||
return [
|
return [
|
||||||
rng(r, baseIndex + 0),
|
rng(r, baseIndex + 0),
|
||||||
rng(g, baseIndex + 1),
|
rng(g, baseIndex + 1),
|
||||||
@ -63,7 +63,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const settings = require("./settings");
|
const settings = require("./settings");
|
||||||
const logging = require("./logging");
|
|
||||||
const extension = require("./extension");
|
const extension = require("./extension");
|
||||||
|
|
||||||
function getDomain(window){
|
function getDomain(window){
|
||||||
@ -81,8 +80,14 @@
|
|||||||
return window.location.host;
|
return window.location.host;
|
||||||
}
|
}
|
||||||
|
|
||||||
var persistentRnd = Object.create(null);
|
let persistentRnd = Object.create(null);
|
||||||
let cookieStoreId = false;
|
let cookieStoreId = false;
|
||||||
|
function getCookieStoreId(){
|
||||||
|
while (cookieStoreId === false){
|
||||||
|
extension.waitSync("to wait for cookie store id");
|
||||||
|
}
|
||||||
|
return cookieStoreId;
|
||||||
|
}
|
||||||
settings.onloaded(function(){
|
settings.onloaded(function(){
|
||||||
try {
|
try {
|
||||||
let storedData = JSON.parse(
|
let storedData = JSON.parse(
|
||||||
@ -90,8 +95,8 @@
|
|||||||
settings.persistentIncognitoRndStorage:
|
settings.persistentIncognitoRndStorage:
|
||||||
settings.persistentRndStorage
|
settings.persistentRndStorage
|
||||||
);
|
);
|
||||||
for (var domain in storedData){
|
for (let domain in storedData){
|
||||||
var value = storedData[domain];
|
const value = storedData[domain];
|
||||||
if (
|
if (
|
||||||
Array.isArray(value) &&
|
Array.isArray(value) &&
|
||||||
value.length === 128 &&
|
value.length === 128 &&
|
||||||
@ -103,7 +108,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e){
|
catch (error){
|
||||||
// JSON is not valid -> ignore it
|
// JSON is not valid -> ignore it
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -111,30 +116,30 @@
|
|||||||
|
|
||||||
extension.message.on(function(data){
|
extension.message.on(function(data){
|
||||||
if (data["canvasBlocker-set-domain-rnd"]){
|
if (data["canvasBlocker-set-domain-rnd"]){
|
||||||
var {domain, incognito, rnd} = data["canvasBlocker-set-domain-rnd"];
|
const {domain, incognito, rnd} = data["canvasBlocker-set-domain-rnd"];
|
||||||
if (incognito === extension.inIncognitoContext){
|
if (incognito === extension.inIncognitoContext){
|
||||||
persistentRnd[domain] = new Uint8Array(rnd);
|
persistentRnd[domain] = new Uint8Array(rnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data["canvasBlocker-clear-domain-rnd"]){
|
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);
|
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){
|
return function getPersistentRnd(window){
|
||||||
while (cookieStoreId === false){
|
const domain = getCookieStoreId() + getDomain(window);
|
||||||
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 (e){
|
|
||||||
logging.verbose("Error in XHR:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var domain = cookieStoreId + getDomain(window);
|
|
||||||
if (!persistentRnd[domain]){
|
if (!persistentRnd[domain]){
|
||||||
// create the (sub-)domains random numbers if not existing
|
// create the (sub-)domains random numbers if not existing
|
||||||
persistentRnd[domain] = new Uint8Array(128);
|
persistentRnd[domain] = new Uint8Array(128);
|
||||||
@ -165,26 +170,26 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
scope.persistent.getRng = function(length, window){
|
scope.persistent.getRng = function(length, window){
|
||||||
var bitSet = new Uint32Array(getPersistentRnd(window).buffer);
|
const bitSet = new Uint32Array(getPersistentRnd(window).buffer);
|
||||||
var bitSetLength = bitSet.length;
|
const bitSetLength = bitSet.length;
|
||||||
return function(i){
|
return function(i){
|
||||||
return bitSet[i % bitSetLength];
|
return bitSet[i % bitSetLength];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
scope.persistent.getBitRng = function(length, window){
|
scope.persistent.getBitRng = function(length, window){
|
||||||
var bitSet = getPersistentRnd(window);
|
const bitSet = getPersistentRnd(window);
|
||||||
|
|
||||||
return function(value, i){
|
return function(value, i){
|
||||||
// use the last 7 bits from the value for the index of the
|
// use the last 7 bits from the value for the index of the
|
||||||
// random number
|
// random number
|
||||||
var index = value & 0x7F;
|
const index = value & 0x7F;
|
||||||
|
|
||||||
// use the last 3 bits from the position and the first bit from
|
// use the last 3 bits from the position and the first bit from
|
||||||
// from the value to get bit to use from the random number
|
// from the value to get bit to use from the random number
|
||||||
var bitIndex = ((i & 0x03) << 1) | (value >>> 7);
|
const bitIndex = ((i & 0x03) << 1) | (value >>> 7);
|
||||||
|
|
||||||
// extract the bit
|
// extract the bit
|
||||||
var bit = (bitSet[index] >>> bitIndex) & 0x01;
|
const bit = (bitSet[index] >>> bitIndex) & 0x01;
|
||||||
|
|
||||||
return bit;
|
return bit;
|
||||||
};
|
};
|
||||||
@ -196,16 +201,17 @@
|
|||||||
return scope.nonPersistent.getRng(length, window);
|
return scope.nonPersistent.getRng(length, window);
|
||||||
};
|
};
|
||||||
scope.constant.getPixelRng = (function(){
|
scope.constant.getPixelRng = (function(){
|
||||||
var colors = Object.create(null);
|
const colors = Object.create(null);
|
||||||
return function getConstantPixelRng(length, window, ignoredColors){
|
return function getConstantPixelRng(length, window, ignoredColors){
|
||||||
var rng = scope.nonPersistent.getValueRng(1024, window);
|
const rng = scope.nonPersistent.getValueRng(1024, window);
|
||||||
|
|
||||||
return function(r, g, b, a, i){ // eslint-disable-line max-params
|
// eslint-disable-next-line max-params
|
||||||
var index = String.fromCharCode(r, g, b, a);
|
return function(r, g, b, a, i){
|
||||||
|
const index = String.fromCharCode(r, g, b, a);
|
||||||
if (ignoredColors[index]){
|
if (ignoredColors[index]){
|
||||||
return [r, g, b, a];
|
return [r, g, b, a];
|
||||||
}
|
}
|
||||||
var color = colors[index];
|
let color = colors[index];
|
||||||
if (!color){
|
if (!color){
|
||||||
color = [
|
color = [
|
||||||
rng(r, 0),
|
rng(r, 0),
|
||||||
@ -224,8 +230,8 @@
|
|||||||
scope.nonPersistent.name = "nonPersistent";
|
scope.nonPersistent.name = "nonPersistent";
|
||||||
scope.nonPersistent.getRng = function(length, window){
|
scope.nonPersistent.getRng = function(length, window){
|
||||||
const maxLength = 0x4000;
|
const maxLength = 0x4000;
|
||||||
var randomI = maxLength;
|
let randomI = maxLength;
|
||||||
var randomNumbers = new Uint32Array(Math.min(maxLength, length));
|
let randomNumbers = new Uint32Array(Math.min(maxLength, length));
|
||||||
return function(i){
|
return function(i){
|
||||||
if (randomI >= randomNumbers.length){
|
if (randomI >= randomNumbers.length){
|
||||||
// refill the random number bucket if empty
|
// refill the random number bucket if empty
|
||||||
@ -235,7 +241,7 @@
|
|||||||
}
|
}
|
||||||
window.crypto.getRandomValues(randomNumbers);
|
window.crypto.getRandomValues(randomNumbers);
|
||||||
}
|
}
|
||||||
var rnd = randomNumbers[randomI];
|
const rnd = randomNumbers[randomI];
|
||||||
randomI += 1;
|
randomI += 1;
|
||||||
|
|
||||||
return rnd;
|
return rnd;
|
||||||
|
@ -10,14 +10,14 @@ const require = function(){
|
|||||||
const scope = window.scope;
|
const scope = window.scope;
|
||||||
|
|
||||||
function getScopeName(module){
|
function getScopeName(module){
|
||||||
var scopeName = module.replace(/^\..*\//, "").replace(/\..+/, "");
|
const scopeName = module.replace(/^\..*\//, "").replace(/\..+/, "");
|
||||||
// console.log(scopeName);
|
// console.log(scopeName);
|
||||||
return scopeName;
|
return scopeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
function require(module){
|
function require(module){
|
||||||
if (module.startsWith(".")){
|
if (module.startsWith(".")){
|
||||||
var scopeName = getScopeName(module);
|
const scopeName = getScopeName(module);
|
||||||
return scope[scopeName];
|
return scope[scopeName];
|
||||||
}
|
}
|
||||||
throw new ReferenceError("Unable to get non relative module " + module + "!");
|
throw new ReferenceError("Unable to get non relative module " + module + "!");
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
(function(){
|
(function(){
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var scope;
|
let scope;
|
||||||
if ((typeof exports) !== "undefined"){
|
if ((typeof exports) !== "undefined"){
|
||||||
scope = exports;
|
scope = exports;
|
||||||
}
|
}
|
||||||
@ -19,23 +19,32 @@
|
|||||||
texts.push({text: text.toLowerCase(), content});
|
texts.push({text: text.toLowerCase(), content});
|
||||||
};
|
};
|
||||||
scope.search = function(search){
|
scope.search = function(search){
|
||||||
const resultSets = search.toLowerCase().split(/\s+/).filter(function(term){
|
const resultSets = search.split(/\s+/).filter(function(term){
|
||||||
return term.trim();
|
return term.trim();
|
||||||
}).map(function(term){
|
|
||||||
return new RegExp(term);
|
|
||||||
}).map(function(term){
|
}).map(function(term){
|
||||||
const matching = new Set();
|
const matching = new Set();
|
||||||
texts.forEach(function(text){
|
if (term.match(/^:[a-z]+$/i)){
|
||||||
if (term.test(text.text)){
|
const tag = term.substring(1);
|
||||||
matching.add(text.content);
|
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;
|
return matching;
|
||||||
});
|
});
|
||||||
if (resultSets.length){
|
if (resultSets.length){
|
||||||
return Array.from(
|
return Array.from(
|
||||||
resultSets.reduce(function(previousSet, set){
|
resultSets.reduce(function(previousSet, set){
|
||||||
var andSet = new Set();
|
const andSet = new Set();
|
||||||
set.forEach(function(entry){
|
set.forEach(function(entry){
|
||||||
if (previousSet.has(entry)){
|
if (previousSet.has(entry)){
|
||||||
andSet.add(entry);
|
andSet.add(entry);
|
||||||
|