├── LICENSE.txt
├── Makefile
├── Plugin
├── Makefile
├── chrome.manifest
├── chrome
│ └── content
│ │ ├── attribute.js
│ │ ├── attribute.xul
│ │ ├── browser.xul
│ │ ├── canvasFingerprinting.xul
│ │ ├── jquery-2.1.0.min.js
│ │ ├── options.js
│ │ ├── options.xul
│ │ ├── overlay.js
│ │ ├── thirdparties.js
│ │ ├── thirdparties.xul
│ │ ├── webidentities.css
│ │ ├── webidentities.js
│ │ └── webidentities.xul
├── defaults
│ └── preferences
│ │ └── defaults.js
├── icon.png
├── install.rdf
├── locale
│ └── en-US
│ │ └── translations.dtd
├── modules
│ ├── detection.jsm
│ ├── httpRequestObserver.jsm
│ ├── preferencesObserver.jsm
│ ├── profiles.jsm
│ ├── randomFingerprintGenerator.jsm
│ ├── responseListener.jsm
│ └── webIdentity.jsm
├── profiles
│ ├── chrome.json
│ ├── firefox.json
│ ├── opera.json
│ └── safari.json
└── skin
│ ├── ajax-loader.gif
│ ├── allow.png
│ ├── block.png
│ ├── cancel.png
│ ├── collapsed.png
│ ├── error.png
│ ├── expanded.png
│ ├── facebook-allowed.png
│ ├── facebook-blocked.png
│ ├── flash-allowed.png
│ ├── flash-blocked.png
│ ├── googleplus-allowed.png
│ ├── googleplus-blocked.png
│ ├── help.png
│ ├── icon32-disabled.png
│ ├── icon32.png
│ ├── icon64-disabled.png
│ ├── icon64.png
│ ├── linkedin-allowed.png
│ ├── linkedin-blocked.png
│ ├── logo.png
│ ├── other-allowed.png
│ ├── other-blocked.png
│ ├── pinterest-allowed.png
│ ├── pinterest-blocked.png
│ ├── private-browsing.png
│ ├── quicktime-allowed.png
│ ├── quicktime-blocked.png
│ ├── settings.png
│ ├── silverlight-allowed.png
│ ├── silverlight-blocked.png
│ ├── skin.css
│ ├── spoof.png
│ ├── toolbar-disabled.png
│ ├── toolbar-icon.png
│ ├── tumblr-allowed.png
│ ├── tumblr-blocked.png
│ ├── twitter-allowed.png
│ ├── twitter-blocked.png
│ ├── vlc-allowed.png
│ └── vlc-blocked.png
└── README.md
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | plugindir=Plugin
2 |
3 | all: ${plugindir}/*
4 | $(MAKE) -C $(plugindir)
5 |
--------------------------------------------------------------------------------
/Plugin/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | zip -9r ../FP-Block.xpi *
3 | zip -d ../FP-Block.xpi Makefile README.txt *.DS_Store*
4 |
--------------------------------------------------------------------------------
/Plugin/chrome.manifest:
--------------------------------------------------------------------------------
1 | content fpblock chrome/content/
2 | content fpblock chrome/content/ contentaccessible=yes
3 | resource modules modules/
4 | resource profiles profiles/
5 | overlay chrome://browser/content/browser.xul chrome://fpblock/content/browser.xul
6 |
7 | locale fpblock en-US locale/en-US/
8 |
9 | skin fpblock classic/1.0 skin/
10 | style chrome://global/content/customizeToolbar.xul chrome://fpblock/skin/skin.css
--------------------------------------------------------------------------------
/Plugin/chrome/content/attribute.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 02.02.2015 */
5 | /****************************************************************/
6 |
7 | Components.utils.import("resource://modules/webIdentity.jsm");
8 | Components.utils.import("resource://modules/detection.jsm");
9 | Components.utils.import("resource://modules/randomFingerprintGenerator.jsm");
10 |
11 | // Called once when the dialog displays
12 | function onLoad() {
13 | if (window.arguments != null) {
14 | // Get web identity
15 | var webID = webIdentity.getWebIdentity(window.arguments[0].url);
16 | // Get attribute
17 | var attribute = detection.getAttribute(window.arguments[0].url, window.arguments[0].name);
18 | // Set the domain name
19 | document.getElementById('domain-name').value = "Domain: "+webID.domain;
20 | // Set the attribute name
21 | document.getElementById('attribute-name').value = attribute.name;
22 | // Set the attribute action
23 | document.getElementById('attribute-action').value = attribute.action;
24 |
25 | document.getElementById('attribute-action').getItemAtIndex(1).hidden = false;
26 | document.getElementById('attribute-label-value').hidden = true;
27 | document.getElementById('attribute-value').hidden = true;
28 |
29 | if (attribute.name == 'App Code Name') {
30 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.appCodeName;
31 | document.getElementById('attribute-label-value').hidden = false;
32 | document.getElementById('attribute-value').hidden = false;
33 | } else
34 | if (attribute.name == 'App Name') {
35 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.appName;
36 | document.getElementById('attribute-label-value').hidden = false;
37 | document.getElementById('attribute-value').hidden = false;
38 | } else
39 | if (attribute.name == 'App Version') {
40 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.appVersion;
41 | document.getElementById('attribute-label-value').hidden = false;
42 | document.getElementById('attribute-value').hidden = false;
43 | } else
44 | if (attribute.name == 'Language') {
45 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.language;
46 | document.getElementById('attribute-label-value').hidden = false;
47 | document.getElementById('attribute-value').hidden = false;
48 | } else
49 | if (attribute.name == 'OS CPU') {
50 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.oscpu;
51 | document.getElementById('attribute-label-value').hidden = false;
52 | document.getElementById('attribute-value').hidden = false;
53 | } else
54 | if (attribute.name == 'Platform') {
55 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.platform;
56 | document.getElementById('attribute-label-value').hidden = false;
57 | document.getElementById('attribute-value').hidden = false;
58 | } else
59 | if (attribute.name == 'Product') {
60 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.product;
61 | document.getElementById('attribute-label-value').hidden = false;
62 | document.getElementById('attribute-value').hidden = false;
63 | } else
64 | if (attribute.name == 'User-Agent') {
65 | document.getElementById('attribute-value').value = webID.fingerprint.useragent;
66 | document.getElementById('attribute-label-value').hidden = false;
67 | document.getElementById('attribute-value').hidden = false;
68 | } else
69 | if (attribute.name == 'Vendor') {
70 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.vendor;
71 | document.getElementById('attribute-label-value').hidden = false;
72 | document.getElementById('attribute-value').hidden = false;
73 | } else
74 | if (attribute.name == 'CPU Class') {
75 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.cpuClass;
76 | document.getElementById('attribute-label-value').hidden = false;
77 | document.getElementById('attribute-value').hidden = false;
78 | } else
79 | if (attribute.name == 'System Language') {
80 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.systemLanguage;
81 | document.getElementById('attribute-label-value').hidden = false;
82 | document.getElementById('attribute-value').hidden = false;
83 | } else
84 | if (attribute.name == 'User Language') {
85 | document.getElementById('attribute-value').value = webID.fingerprint.navigator.userLanguage;
86 | document.getElementById('attribute-label-value').hidden = false;
87 | document.getElementById('attribute-value').hidden = false;
88 | } else
89 | if (attribute.name == 'Screen Height') {
90 | document.getElementById('attribute-value').value = webID.fingerprint.screen.height;
91 | document.getElementById('attribute-label-value').hidden = false;
92 | document.getElementById('attribute-value').hidden = false;
93 | } else
94 | if (attribute.name == 'Screen Width') {
95 | document.getElementById('attribute-value').value = webID.fingerprint.screen.width;
96 | document.getElementById('attribute-label-value').hidden = false;
97 | document.getElementById('attribute-value').hidden = false;
98 | } else
99 | if (attribute.name == 'Color Depth') {
100 | document.getElementById('attribute-value').value = webID.fingerprint.screen.colorDepth;
101 | document.getElementById('attribute-label-value').hidden = false;
102 | document.getElementById('attribute-value').hidden = false;
103 | } else
104 | if (attribute.name == 'Available Height') {
105 | document.getElementById('attribute-value').value = webID.fingerprint.screen.availHeight;
106 | document.getElementById('attribute-label-value').hidden = false;
107 | document.getElementById('attribute-value').hidden = false;
108 | } else
109 | if (attribute.name == 'Available Width') {
110 | document.getElementById('attribute-value').value = webID.fingerprint.screen.availWidth;
111 | document.getElementById('attribute-label-value').hidden = false;
112 | document.getElementById('attribute-value').hidden = false;
113 | } else
114 | if (attribute.name == 'Pixel Depth') {
115 | document.getElementById('attribute-value').value = webID.fingerprint.screen.pixelDepth;
116 | document.getElementById('attribute-label-value').hidden = false;
117 | document.getElementById('attribute-value').hidden = false;
118 | } else
119 | if (attribute.name == 'Timezone') {
120 | document.getElementById('attribute-value').value = webID.fingerprint.date.timezoneOffset;
121 | document.getElementById('attribute-label-value').hidden = false;
122 | document.getElementById('attribute-value').hidden = false;
123 | } else {
124 | document.getElementById('attribute-action').getItemAtIndex(1).hidden = true;
125 | }
126 | }
127 | }
128 |
129 | function actionSelected() {
130 | // Enable respectively disable the attribute value if the seleted action is 'spoof'
131 | if (document.getElementById('attribute-action').value == 'spoof') {
132 | document.getElementById('attribute-value').disabled = false;
133 | } else {
134 | document.getElementById('attribute-value').disabled = true;
135 | }
136 | }
137 |
138 | function acceptEdit() {
139 | // Display warning
140 | alert('Warning: Modifying the value of an attribute can break consistency!');
141 | // Get web identity
142 | var webID = webIdentity.getWebIdentity(window.arguments[0].url);
143 | // Get attribute
144 | var attribute = detection.getAttribute(window.arguments[0].url, window.arguments[0].name);
145 | // Save the attribute action
146 | attribute.action = document.getElementById('attribute-action').value;
147 | // Save the edited attribute
148 | if (document.getElementById('attribute-action').value == 'spoof') {
149 | if (attribute.name == 'App Code Name') {
150 | webID.fingerprint.navigator.appCodeName = document.getElementById('attribute-value').value;
151 | } else
152 | if (attribute.name == 'App Name') {
153 | webID.fingerprint.navigator.appName = document.getElementById('attribute-value').value;
154 | } else
155 | if (attribute.name == 'App Version') {
156 | webID.fingerprint.navigator.appVersion = document.getElementById('attribute-value').value;
157 | } else
158 | if (attribute.name == 'Language') {
159 | webID.fingerprint.navigator.language = document.getElementById('attribute-value').value;
160 | } else
161 | if (attribute.name == 'OS CPU') {
162 | webID.fingerprint.navigator.oscpu = document.getElementById('attribute-value').value;
163 | } else
164 | if (attribute.name == 'Platform') {
165 | webID.fingerprint.navigator.platform = document.getElementById('attribute-value').value;
166 | } else
167 | if (attribute.name == 'Product') {
168 | webID.fingerprint.navigator.product = document.getElementById('attribute-value').value;
169 | } else
170 | if (attribute.name == 'User-Agent') {
171 | webID.fingerprint.useragent = document.getElementById('attribute-value').value;
172 | } else
173 | if (attribute.name == 'Vendor') {
174 | webID.fingerprint.navigator.vendor = document.getElementById('attribute-value').value;
175 | } else
176 | if (attribute.name == 'CPU Class') {
177 | webID.fingerprint.navigator.cpuClass = document.getElementById('attribute-value').value;
178 | } else
179 | if (attribute.name == 'System Language') {
180 | webID.fingerprint.navigator.systemLanguage = document.getElementById('attribute-value').value;
181 | } else
182 | if (attribute.name == 'User Language') {
183 | webID.fingerprint.navigator.userLanguage = document.getElementById('attribute-value').value;
184 | } else
185 | if (attribute.name == 'Screen Height') {
186 | webID.fingerprint.screen.height = document.getElementById('attribute-value').value;
187 | } else
188 | if (attribute.name == 'Screen Width') {
189 | webID.fingerprint.screen.width = document.getElementById('attribute-value').value;
190 | } else
191 | if (attribute.name == 'Color Depth') {
192 | webID.fingerprint.screen.colorDepth = document.getElementById('attribute-value').value;
193 | } else
194 | if (attribute.name == 'Available Height') {
195 | webID.fingerprint.screen.availHeight = document.getElementById('attribute-value').value;
196 | } else
197 | if (attribute.name == 'Available Width') {
198 | webID.fingerprint.screen.availWidth = document.getElementById('attribute-value').value;
199 | } else
200 | if (attribute.name == 'Pixel Depth') {
201 | webID.fingerprint.screen.pixelDepth = document.getElementById('attribute-value').value;
202 | } else
203 | if (attribute.name == 'Timezone') {
204 | webID.fingerprint.date.timezoneOffset = document.getElementById('attribute-value').value;
205 | }
206 | }
207 | // Save the new generated hash
208 | webID.hash = randomFingerprintGenerator.generateHash(webID.fingerprint);
209 | }
210 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/attribute.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/browser.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/canvasFingerprinting.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | .message {
12 | width: 300px;
13 | margin-left: 10px;
14 | text-align: justify;
15 | }
16 |
17 | .title {
18 | font-size: 14px;
19 | margin-bottom: 10px;
20 | }
21 |
22 |
23 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Canvas fingerprinting detection
41 | This website attempted to
42 | access image data on a canvas. Since canvas image data can be
43 | used to discover information about your computer, FP-Block
44 | returned the original image data with some random noise added
45 | to it.
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/options.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 26.08.2015 */
5 | /****************************************************************/
6 |
7 | window.onload = function() {
8 | getAddonNameVer(function(addon) {
9 | document.getElementById('version').value = addon.name + " " + addon.version;
10 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
11 | if (fpblockpreferences.getCharPref('latestfetch') == '') {
12 | document.getElementById('latest-fetch').value = "Last time fetched: never";
13 | } else {
14 | var latestfetch = new Date(parseInt(fpblockpreferences.getCharPref('latestfetch')));
15 | var day = (String(latestfetch.getDate()).length == 1) ? "0" + latestfetch.getDate() : latestfetch.getDate();
16 | var month = (String(latestfetch.getMonth() + 1).length == 1) ? "0" + (latestfetch.getMonth() + 1) : latestfetch.getMonth() + 1;
17 | var year = latestfetch.getFullYear();
18 | var hour = (String(latestfetch.getHours()).length == 1) ? "0" + latestfetch.getHours() : latestfetch.getHours();
19 | var minutes = (String(latestfetch.getMinutes()).length == 1) ? "0" + latestfetch.getMinutes() : latestfetch.getMinutes();
20 | var seconds = (String(latestfetch.getSeconds()).length == 1) ? "0" + latestfetch.getSeconds() : latestfetch.getSeconds();
21 | document.getElementById('latest-fetch').value = "Last time fetched: " + day + "/" + month + "/" + year + " " + hour + ":" + minutes + ":" + seconds;
22 | }
23 | });
24 | };
25 |
26 | function getAddonNameVer(callback) {
27 | Components.utils.import("resource://gre/modules/AddonManager.jsm");
28 | AddonManager.getAddonByID('fpblock@fingerprint.christoftorres.com', callback);
29 | }
30 |
31 | function blockThirdParties() {
32 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
33 | var cookieBehaviour = !fpblockpreferences.getBoolPref('blockthirdparties');
34 | var firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.cookie.');
35 | if (cookieBehaviour) {
36 | firefoxpreferences.setIntPref('cookieBehavior', 1);
37 | } else {
38 | firefoxpreferences.setIntPref('cookieBehavior', 0);
39 | }
40 | }
41 |
42 | function setDNTHeader() {
43 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
44 | var enabled = !fpblockpreferences.getBoolPref('dntheader');
45 | var firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('privacy.donottrackheader.');
46 | firefoxpreferences.setBoolPref('enabled', enabled);
47 | if (enabled) {
48 | firefoxpreferences.setIntPref('value', 1);
49 | } else {
50 | firefoxpreferences.setIntPref('value', 0);
51 | }
52 | }
53 |
54 | function blockAutomaticConnections() {
55 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
56 | var enabled = !fpblockpreferences.getBoolPref('autoblockconnections');
57 | // Page preloading
58 | var firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.http.');
59 | if (enabled) {
60 | firefoxpreferences.setIntPref('speculative-parallel-limit', 0);
61 | } else {
62 | firefoxpreferences.setIntPref('speculative-parallel-limit', 6);
63 | }
64 | // DNS prefetching
65 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.dns.');
66 | if (enabled) {
67 | firefoxpreferences.setBoolPref('disablePrefetch', true);
68 | } else {
69 | firefoxpreferences.setBoolPref('disablePrefetch', false);
70 | }
71 | // Link prefetching
72 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.');
73 | if (enabled) {
74 | firefoxpreferences.setBoolPref('prefetch-next', false);
75 | } else {
76 | firefoxpreferences.setBoolPref('prefetch-next', true);
77 | }
78 | }
79 |
80 | function resetDefaultSettings() {
81 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
82 | // General preferences
83 | fpblockpreferences.setBoolPref('notifydetections', true);
84 | // HTTP preferences
85 | fpblockpreferences.setBoolPref('blockthirdparties', true);
86 | //fpblockpreferences.setBoolPref('deletereferer', true);
87 | fpblockpreferences.setBoolPref('dntheader', true);
88 | fpblockpreferences.setBoolPref('deleteetags', true);
89 | // JavaScript preferences
90 | fpblockpreferences.setBoolPref('autoblocksocial', false);
91 | fpblockpreferences.setBoolPref('autoblockplugins', true);
92 | // Firefox automatic connections preferences
93 | fpblockpreferences.setBoolPref('autoblockconnections', true);
94 | // Debugging mode
95 | fpblockpreferences.setBoolPref('debuggingmode', false);
96 |
97 | var firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.cookie.');
98 | firefoxpreferences.setIntPref('cookieBehavior', 1);
99 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('privacy.donottrackheader.');
100 | firefoxpreferences.setBoolPref('enabled', true);
101 | firefoxpreferences.setIntPref('value', 1);
102 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.http.');
103 | firefoxpreferences.setIntPref('speculative-parallel-limit', 0);
104 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.dns.');
105 | firefoxpreferences.setBoolPref('disablePrefetch', true);
106 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.');
107 | firefoxpreferences.setBoolPref('prefetch-next', false);
108 | }
109 |
110 | Components.utils.import("resource://modules/profiles.jsm");
111 |
112 | function fetchLatestProfiles() {
113 | var loader = document.getElementById('ajax-loader');
114 | loader.style.visibility = 'visible';
115 | var path = "http://christoftorres.no-ip.org/Experiments/profiles/";
116 | var files = ["chrome.json", "firefox.json", "opera.json", "safari.json"];
117 | var xmlhttp = new XMLHttpRequest();
118 | var index = 0;
119 | profiles = [];
120 | xmlhttp.onreadystatechange = function() {
121 | if (xmlhttp.readyState == 4) {
122 | if (xmlhttp.status == 200) {
123 | profiles.push(JSON.parse(xmlhttp.responseText));
124 | index++;
125 | if (index != files.length) {
126 | xmlhttp.open("POST", path+files[index], true);
127 | xmlhttp.send();
128 | } else {
129 | var fpblockpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('extensions.fpblock.');
130 | fpblockpreferences.setCharPref('latestfetch', new Date().getTime());
131 | var latestfetch = new Date(parseInt(fpblockpreferences.getCharPref('latestfetch')));
132 | var day = (String(latestfetch.getDate()).length == 1) ? "0" + latestfetch.getDate() : latestfetch.getDate();
133 | var month = (String(latestfetch.getMonth() + 1).length == 1) ? "0" + (latestfetch.getMonth() + 1) : latestfetch.getMonth() + 1;
134 | var year = latestfetch.getFullYear();
135 | var hour = (String(latestfetch.getHours()).length == 1) ? "0" + latestfetch.getHours() : latestfetch.getHours();
136 | var minutes = (String(latestfetch.getMinutes()).length == 1) ? "0" + latestfetch.getMinutes() : latestfetch.getMinutes();
137 | var seconds = (String(latestfetch.getSeconds()).length == 1) ? "0" + latestfetch.getSeconds() : latestfetch.getSeconds();
138 | document.getElementById('latest-fetch').value = "Last time fetched: " + day + "/" + month + "/" + year + " " + hour + ":" + minutes + ":" + seconds;
139 | loader.style.visibility = 'hidden';
140 | }
141 | }
142 | }
143 | }
144 | xmlhttp.open("POST", path+files[index], true);
145 | xmlhttp.send();
146 | }
--------------------------------------------------------------------------------
/Plugin/chrome/content/options.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 | .addon-version {
12 | font-weight: bold;
13 | margin: 15px;
14 | }
15 |
16 | .about-groupbox {
17 | padding-top: 15px;
18 | margin-bottom: 15px;
19 | max-width: 420px;
20 | min-height: 370px;
21 | }
22 |
23 | .about-info-left {
24 | float: left;
25 | padding: 35px 10px 10px 10px;
26 | min-width: 210px;
27 | max-width: 210px;
28 | text-align: center;
29 | }
30 |
31 | .about-info-right {
32 | float: right;
33 | padding: 10px;
34 | min-width: 210px;
35 | max-width: 210px;
36 | text-align: justify;
37 | }
38 |
39 | .author {
40 | margin-top: 20px;
41 | text-align: right;
42 | }
43 |
44 | .checkbox {
45 | width: 600px;
46 | }
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | FP-Block helps you to preserve privacy on the web with respect to browser fingerptinting. FP-Block aims to keep your web identities seperate through creating unique web identites for each website you visit. It allows you to block social plugins and to block individual browser plugins. Furthermore, it allows you to detect third-parties and to block, allow or spoof JavaScript attributes that a website tries to read. Please note that FP-Block is solely a proof-of-concept.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/overlay.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 05.09.2015 */
5 | /****************************************************************/
6 |
7 | Components.utils.import("resource://modules/webIdentity.jsm");
8 | Components.utils.import("resource://modules/detection.jsm");
9 | Components.utils.import("resource://modules/httpRequestObserver.jsm");
10 | Components.utils.import("resource://modules/preferencesObserver.jsm");
11 |
12 | var Cc = Components.classes;
13 | var Ci = Components.interfaces;
14 |
15 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
16 |
17 | var fpBlock = new function() {
18 | var previousdomain = null;
19 | return {
20 | init : function() {
21 | try {
22 | // Install toolbar button at the first run
23 | if (preferences.getBoolPref("firstrun")) {
24 | // https://developer.mozilla.org/en-US/docs/Code_snippets/Toolbar
25 | /**
26 | * Installs the toolbar button with the given ID into the given
27 | * toolbar, if it is not already present in the document.
28 | *
29 | * @param {string} toolbarId The ID of the toolbar to install to.
30 | * @param {string} id The ID of the button to install.
31 | * @param {string} afterId The ID of the element to insert after. @optional
32 | */
33 | function installButton(toolbarId, id, afterId) {
34 | if (!document.getElementById(id)) {
35 | var toolbar = document.getElementById(toolbarId);
36 |
37 | // If no afterId is given, then append the item to the toolbar
38 | var before = null;
39 | if (afterId) {
40 | let elem = document.getElementById(afterId);
41 | if (elem && elem.parentNode == toolbar)
42 | before = elem.nextElementSibling;
43 | }
44 |
45 | toolbar.insertItem(id, before);
46 | toolbar.setAttribute("currentset", toolbar.currentSet);
47 | document.persist(toolbar.id, "currentset");
48 |
49 | if (toolbarId == "addon-bar")
50 | toolbar.collapsed = false;
51 | }
52 | }
53 | installButton("nav-bar", "fp-block-toolbar-button");
54 | // The "addon-bar" is available since Firefox 4
55 | installButton("addon-bar", "fp-block-toolbar-button");
56 | preferences.setBoolPref("firstrun", false);
57 | // Block third-party cookies
58 | var firefoxpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('network.cookie.');
59 | firefoxpreferences.setIntPref('cookieBehavior', 1);
60 | }
61 | // Get the tab container
62 | var container = gBrowser.tabContainer;
63 | // Add an event listener to the event of opening a new tab
64 | container.addEventListener("TabOpen", fpBlock.tabOpen, false);
65 | // Add an event listener to the event of clicking on an open tab
66 | container.addEventListener("TabSelect", fpBlock.tabSelect, false);
67 | // Add an event listener when the page (tab) has loaded
68 | gBrowser.addEventListener("load", fpBlock.pageLoad, true);
69 | // Get the script loader
70 | var loader = Cc['@mozilla.org/moz/jssubscript-loader;1'].getService(Ci.mozIJSSubScriptLoader);
71 | // Load jQuery 2.1.0
72 | loader.loadSubScript('chrome://fpblock/content/jquery-2.1.0.min.js', this);
73 | // Load web identities
74 | webIdentity.loadWebIdentities();
75 | // Load detections
76 | detection.loadDetections();
77 | // Register the HTTP request observer
78 | httpRequestObserver.register();
79 | // Register the third-party cookies preferences observer
80 | preferencesThirdPartiesObserver.register();
81 | // Register the DNT header preferences observer
82 | preferencesDNTObserver.register();
83 | // Register the automatic connections preferences observer
84 | preferencesAutomaticConnectionsObserver.register();
85 | // Set the block third-party cookies preference
86 | var cookieBehaviour = preferences.getBoolPref('blockthirdparties');
87 | var firefoxpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('network.cookie.');
88 | if (cookieBehaviour) {
89 | firefoxpreferences.setIntPref('cookieBehavior', 1);
90 | } else {
91 | firefoxpreferences.setIntPref('cookieBehavior', 0);
92 | }
93 | // Set the DNT header preference
94 | var enabled = preferences.getBoolPref('dntheader');
95 | firefoxpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('privacy.donottrackheader.');
96 | firefoxpreferences.setBoolPref('enabled', enabled);
97 | if (enabled) {
98 | firefoxpreferences.setIntPref('value', 1);
99 | } else {
100 | firefoxpreferences.setIntPref('value', 0);
101 | }
102 | // Set block automatic connections preference
103 | enabled = preferences.getBoolPref('autoblockconnections');
104 | /* Page preloading */
105 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.http.');
106 | if (enabled) {
107 | firefoxpreferences.setIntPref('speculative-parallel-limit', 0);
108 | } else {
109 | firefoxpreferences.setIntPref('speculative-parallel-limit', 6);
110 | }
111 | /* DNS prefetching */
112 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.dns.');
113 | if (enabled) {
114 | firefoxpreferences.setBoolPref('disablePrefetch', true);
115 | } else {
116 | firefoxpreferences.setBoolPref('disablePrefetch', false);
117 | }
118 | /* Link prefetching */
119 | firefoxpreferences = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefService).getBranch('network.');
120 | if (enabled) {
121 | firefoxpreferences.setBoolPref('prefetch-next', false);
122 | } else {
123 | firefoxpreferences.setBoolPref('prefetch-next', true);
124 | }
125 | } catch(e) {
126 | alert('Error initializing FP-Block!');
127 | }
128 | },
129 |
130 | tabOpen : function(event) {
131 | fpBlock.toggleToolbarButton(gBrowser.getBrowserForTab(event.target));
132 | },
133 |
134 | tabSelect : function(event) {
135 | fpBlock.toggleToolbarButton(gBrowser.selectedBrowser);
136 | },
137 |
138 | pageLoad : function(event) {
139 | fpBlock.toggleToolbarButton(gBrowser.selectedBrowser);
140 | },
141 |
142 | showPopupMenu : function() {
143 | var domain = null;
144 | try {
145 | document.getElementById('social-plugins').style.display = 'block';
146 | document.getElementById('summary').style.display = 'block';
147 | document.getElementById('browser-plugins').style.display = 'block';
148 | document.getElementById('website-switch').style.display = 'block';
149 | document.getElementById('domain-error').style.display = 'none';
150 |
151 | // Try to get the domain name
152 | var browser = gBrowser.selectedBrowser;
153 | try {
154 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
155 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
156 | } catch(e) {
157 | domain = 'localhost';
158 | }
159 |
160 | // Try to get the web identity
161 | var webID = null;
162 | // Private browsing mode
163 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
164 | webID = privateWebIdentity.getPrivateWebIdentity(domain);
165 | $('#private-browsing').html(' ');
166 | // Normal browsing mode
167 | } else {
168 | webID = webIdentity.getWebIdentity(domain);
169 | $('#private-browsing').html('');
170 | }
171 |
172 | if (previousdomain != domain) {
173 | document.getElementById('attribute-list').style.display = 'none';
174 | document.getElementById('arrow-attributes').src = 'chrome://fpblock/skin/collapsed.png';
175 | document.getElementById('third-parties-list').style.display = 'none';
176 | document.getElementById('arrow-third-parties').src = 'chrome://fpblock/skin/collapsed.png';
177 | document.getElementById('fpblock-popup').style.height = 276 + 'px';
178 | previousdomain = domain;
179 | }
180 |
181 | while (document.getElementById('domain').lastChild) {
182 | document.getElementById('domain').removeChild(document.getElementById('domain').lastChild);
183 | }
184 | document.getElementById('domain').appendChild(document.createTextNode(domain));
185 |
186 | // Social Plugins
187 | try {
188 | var socialplugins = webID.socialplugins;
189 | var socialpluginstable = '
';
190 | socialpluginstable += '';
191 | var numberofsocialplugins = 0;
192 | for (var service in socialplugins) {
193 | if (socialplugins[service] != undefined) {
194 | numberofsocialplugins++;
195 | socialpluginstable += '';
196 | if (socialplugins[service]) {
197 | socialpluginstable += ' ';
198 | } else {
199 | socialpluginstable += ' ';
200 | }
201 | socialpluginstable += ' ';
202 | }
203 | }
204 | if (numberofsocialplugins == 0) {
205 | socialpluginstable += 'No social plugins detected
';
206 | }
207 | socialpluginstable += ' ';
208 | socialpluginstable += '
';
209 | $('#social-plugins-table').html(socialpluginstable);
210 | } catch(e) {
211 | if (preferences.getBoolPref("debuggingmode")) {
212 | $('#social-plugins-table').html(''+e+'
');
213 | } else {
214 | $('#social-plugins-table').html('Error while loading social plugins!
');
215 | }
216 | }
217 |
218 | // Summary
219 | try {
220 | var attributes;
221 | if (detection.getDetection(domain)) {
222 | attributes = detection.getDetection(domain).attributes;
223 | } else {
224 | attributes = [];
225 | }
226 | var attributesSpoofedBlocked = 0;
227 | for (var i = 0; i < attributes.length; i++) {
228 | if (attributes[i].action == 'spoof' || attributes[i].action == 'block') {
229 | attributesSpoofedBlocked++;
230 | }
231 | }
232 | while (document.getElementById('detected-attributes').lastChild) {
233 | document.getElementById('detected-attributes').removeChild(document.getElementById('detected-attributes').lastChild);
234 | }
235 | document.getElementById('detected-attributes').appendChild(document.createTextNode(attributesSpoofedBlocked+"/"+attributes.length));
236 |
237 | var thirdparties = webID.thirdparties;
238 | var thirdpartiesBlocked = 0;
239 | for (var i = 0; i < thirdparties.length; i++) {
240 | if (!thirdparties[i].enabled) {
241 | thirdpartiesBlocked++;
242 | }
243 | }
244 | while (document.getElementById('detected-third-parties').lastChild) {
245 | document.getElementById('detected-third-parties').removeChild(document.getElementById('detected-third-parties').lastChild);
246 | }
247 | document.getElementById('detected-third-parties').appendChild(document.createTextNode(thirdpartiesBlocked+"/"+thirdparties.length));
248 |
249 | // Detected attributes
250 | $('#attribute-list').html('');
251 | var serviceSurface = $(document.getElementById('attribute-list'));
252 | var serviceTemplate = $(document).find('.attribute');
253 | serviceTemplate.show();
254 | for (var i = 0; i < attributes.length; i++) {
255 | var serviceControl = serviceTemplate.clone(true);
256 | serviceControl.find('.attribute-label').text(attributes[i].name);
257 | var checkbox = serviceControl[0].getElementsByTagName('html:input')[0];
258 | if (attributes[i].name == 'Plugins' || attributes[i].name == 'Mime Types') {
259 | checkbox.disabled = true;
260 | }
261 | if (attributes[i].action == "allow") {
262 | checkbox.checked = true;
263 | } else {
264 | checkbox.checked = false;
265 | }
266 | checkbox.onclick = function(checkbox, attribute) {
267 | if (checkbox.checked) {
268 | attribute.action = "allow";
269 | } else {
270 | if (attribute.name == 'App Code Name' ||
271 | attribute.name == 'App Name' ||
272 | attribute.name == 'App Version' ||
273 | attribute.name == 'Language' ||
274 | attribute.name == 'OS CPU' ||
275 | attribute.name == 'Platform' ||
276 | attribute.name == 'Product' ||
277 | attribute.name == 'User-Agent' ||
278 | attribute.name == 'Vendor' ||
279 | attribute.name == 'CPU Class' ||
280 | attribute.name == 'System Language' ||
281 | attribute.name == 'User Language' ||
282 | attribute.name == 'Screen Height' ||
283 | attribute.name == 'Screen Width' ||
284 | attribute.name == 'Color Depth' ||
285 | attribute.name == 'Available Height' ||
286 | attribute.name == 'Available Width' ||
287 | attribute.name == 'Pixel Depth' ||
288 | attribute.name == 'Timezone') {
289 | attribute.action = "spoof";
290 | } else {
291 | attribute.action = "block";
292 | }
293 | }
294 | content.location.reload();
295 | }.bind(null, checkbox, attributes[i]);
296 | serviceSurface.append(serviceControl);
297 | }
298 | serviceTemplate.hide();
299 |
300 | // Third-Parties
301 | $('#third-parties-list').html('');
302 | var serviceSurface = $(document.getElementById('third-parties-list'));
303 | var serviceTemplate = $(document).find('.third-party');
304 | serviceTemplate.show();
305 | for (var i = 0; i < thirdparties.length; i++) {
306 | var serviceControl = serviceTemplate.clone(true);
307 | serviceControl.find('.third-party-label').text(thirdparties[i].name);
308 | var checkbox = serviceControl[0].getElementsByTagName('html:input')[0];
309 | checkbox.checked = thirdparties[i].enabled;
310 | checkbox.onclick = function(checkbox, thirdparty) {
311 | thirdparty.enabled = checkbox.checked;
312 | content.location.reload();
313 | }.bind(null, checkbox, thirdparties[i]);
314 | serviceSurface.append(serviceControl);
315 | }
316 | serviceTemplate.hide();
317 | } catch(e) {
318 | if (preferences.getBoolPref("debuggingmode")) {
319 | $('#summary-list').html(''+e+'
');
320 | } else {
321 | $('#summary-list').html('Error while loading summary!
');
322 | }
323 | }
324 |
325 | // Browser Plugins
326 | try {
327 | var browserplugins = webID.browserplugins;
328 | var browserpluginstable = '';
329 | browserpluginstable += '';
330 | var otherplugins = false;
331 | for (var i = 0; i < navigator.plugins.length; i++) {
332 | if (navigator.plugins[i].name.indexOf("Flash") != -1) {
333 | browserpluginstable += '';
334 | if (browserplugins.flash) {
335 | browserpluginstable += ' ';
336 | } else {
337 | browserpluginstable += ' ';
338 | }
339 | browserpluginstable += ' ';
340 | }
341 | else
342 | if (navigator.plugins[i].name.indexOf("Silverlight") != -1) {
343 | browserpluginstable += '';
344 | if (browserplugins.silverlight) {
345 | browserpluginstable += ' ';
346 | } else {
347 | browserpluginstable += ' ';
348 | }
349 | browserpluginstable += ' ';
350 | }
351 | else
352 | if (navigator.plugins[i].name.indexOf("VLC") != -1) {
353 | browserpluginstable += '';
354 | if (browserplugins.vlc) {
355 | browserpluginstable += ' ';
356 | } else {
357 | browserpluginstable += ' ';
358 | }
359 | browserpluginstable += ' ';
360 | }
361 | else
362 | if (navigator.plugins[i].name.indexOf("QuickTime") != -1) {
363 | browserpluginstable += '';
364 | if (browserplugins.quicktime) {
365 | browserpluginstable += ' ';
366 | } else {
367 | browserpluginstable += ' ';
368 | }
369 | browserpluginstable += ' ';
370 | } else {
371 | otherplugins = true;
372 | }
373 | }
374 | if (otherplugins) {
375 | browserpluginstable += '';
376 | if (browserplugins.other) {
377 | browserpluginstable += ' ';
378 | } else {
379 | browserpluginstable += ' ';
380 | }
381 | browserpluginstable += ' ';
382 | }
383 | if (navigator.plugins.length == 0) {
384 | browserpluginstable += 'No browser plugins detected
';
385 | }
386 | browserpluginstable += ' ';
387 | browserpluginstable += '
';
388 | $('#browser-plugins-table').html(browserpluginstable);
389 | } catch(e) {
390 | if (preferences.getBoolPref("debuggingmode")) {
391 | $('#browser-plugins-table').html(''+e+'
');
392 | } else {
393 | $('#browser-plugins-table').html('Error while loading browser plugins!
');
394 | }
395 | }
396 |
397 | document.getElementById('websiteonoffswitch').checked = webID.enabled;
398 | } catch(e) {
399 | document.getElementById('social-plugins').style.display = 'none';
400 | document.getElementById('summary').style.display = 'none';
401 | document.getElementById('browser-plugins').style.display = 'none';
402 | document.getElementById('website-switch').style.display = 'none';
403 | document.getElementById('domain-error').style.display = 'block';
404 | document.getElementById('fpblock-popup').style.height = 276 + 'px';
405 |
406 | while (document.getElementById('domain').lastChild) {
407 | document.getElementById('domain').removeChild(document.getElementById('domain').lastChild);
408 | }
409 | document.getElementById('domain').appendChild(document.createTextNode(domain));
410 |
411 | if (preferences.getBoolPref("debuggingmode")) {
412 | $('#domain-error').html(''+e+'
');
413 | } else {
414 | $('#domain-error').html('FP-Block stopped working! :(
');
415 | }
416 | }
417 | },
418 |
419 | openPreferences : function() {
420 | window.openDialog("chrome://fpblock/content/options.xul", "fpblock-preferences-window", "chrome, titlebar, toolbar, centerscreen, dialog=no, modal").focus();
421 | },
422 |
423 | toggleSocialPlugins : function(service) {
424 | var browser = gBrowser.selectedBrowser;
425 | var domain = null;
426 |
427 | // Try to get the domain name
428 | try {
429 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
430 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
431 | } catch(e) {
432 | domain = 'localhost';
433 | }
434 |
435 | // Try to get the social plugins
436 | var socialplugins = null
437 | try {
438 | // Private browsing mode
439 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
440 | socialplugins = privateWebIdentity.getPrivateWebIdentity(domain).socialplugins;
441 | // Normal browsing mode
442 | } else {
443 | socialplugins = webIdentity.getWebIdentity(domain).socialplugins;
444 | }
445 | } catch(e) {
446 | alert(e);
447 | }
448 |
449 | if (socialplugins.hasOwnProperty(service)) {
450 | socialplugins[service] = !socialplugins[service];
451 | }
452 | content.location.reload();
453 | },
454 |
455 | toggleAttributes : function() {
456 | var browser = gBrowser.selectedBrowser;
457 | var domain = null;
458 |
459 | // Try to get the domain name
460 | try {
461 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
462 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
463 | } catch(e) {
464 | domain = 'localhost';
465 | }
466 |
467 | // Try to get the attributes
468 | var attributes = null;
469 | try {
470 | attributes = detection.getDetection(domain).attributes;
471 | } catch(e) {
472 | attributes = [];
473 | }
474 | document.getElementById('third-parties-list').style.display = 'none';
475 | document.getElementById('arrow-third-parties').src = 'chrome://fpblock/skin/collapsed.png';
476 | if (document.getElementById('attribute-list').style.display == 'block') {
477 | document.getElementById('attribute-list').style.display = 'none';
478 | document.getElementById('arrow-attributes').src = 'chrome://fpblock/skin/collapsed.png';
479 | document.getElementById('fpblock-popup').style.height = 276 + 'px';
480 | } else {
481 | document.getElementById('attribute-list').style.display = 'block';
482 | document.getElementById('arrow-attributes').src = 'chrome://fpblock/skin/expanded.png';
483 | document.getElementById('fpblock-popup').style.height = 276 + 21 * attributes.length + 'px';
484 | }
485 | },
486 |
487 | toggleThirdParties : function() {
488 | var browser = gBrowser.selectedBrowser;
489 | var domain = null;
490 |
491 | // Try to get the domain name
492 | try {
493 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
494 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
495 | } catch(e) {
496 | domain = 'localhost';
497 | }
498 |
499 | // Try to get the third parties
500 | var thirdparties = null;
501 | try {
502 | // Private browsing mode
503 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
504 | thirdparties = privateWebIdentity.getPrivateWebIdentity(domain).thirdparties;
505 | // Normal browsing mode
506 | } else {
507 | thirdparties = webIdentity.getWebIdentity(domain).thirdparties;
508 | }
509 | } catch(e) {
510 | alert(e);
511 | }
512 |
513 | document.getElementById('attribute-list').style.display = 'none';
514 | document.getElementById('arrow-attributes').src = 'chrome://fpblock/skin/collapsed.png';
515 | if (document.getElementById('third-parties-list').style.display == 'block') {
516 | document.getElementById('third-parties-list').style.display = 'none';
517 | document.getElementById('arrow-third-parties').src = 'chrome://fpblock/skin/collapsed.png';
518 | document.getElementById('fpblock-popup').style.height = 276 + 'px';
519 | } else {
520 | document.getElementById('third-parties-list').style.display = 'block';
521 | document.getElementById('arrow-third-parties').src = 'chrome://fpblock/skin/expanded.png';
522 | document.getElementById('fpblock-popup').style.height = 276 + 21 * thirdparties.length + 'px';
523 | }
524 | },
525 |
526 | toggleBrowserPlugins : function(plugin) {
527 | var browser = gBrowser.selectedBrowser;
528 | var domain = null;
529 |
530 | // Try to get the domain name
531 | try {
532 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
533 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
534 | } catch(e) {
535 | domain = 'localhost';
536 | }
537 |
538 | // Try to get the browser plugins
539 | var browserplugins = null;
540 | try {
541 | // Private browsing mode
542 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
543 | browserplugins = privateWebIdentity.getPrivateWebIdentity(domain).browserplugins;
544 | // Normal browsing mode
545 | } else {
546 | browserplugins = webIdentity.getWebIdentity(domain).browserplugins;
547 | }
548 | } catch(e) {
549 | alert(e);
550 | }
551 |
552 | if (browserplugins.hasOwnProperty(plugin)) {
553 | browserplugins[plugin] = !browserplugins[plugin];
554 | }
555 | content.location.reload();
556 | },
557 |
558 | toggleWebsite : function() {
559 | var browser = gBrowser.selectedBrowser;
560 | var domain = null;
561 |
562 | // Try to get the domain name
563 | try {
564 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
565 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
566 | } catch(e) {
567 | domain = 'localhost';
568 | }
569 |
570 | // Try to enable/disable the website
571 | try {
572 | // Private browsing mode
573 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
574 | privateWebIdentity.getPrivateWebIdentity(domain).enabled = !privateWebIdentity.getPrivateWebIdentity(domain).enabled;
575 | // Disable/enable toolbar-icon
576 | document.getElementById("fp-block-toolbar-button").setAttribute("fpblockActivated", privateWebIdentity.getPrivateWebIdentity(domain).enabled);
577 | // Normal browsing mode
578 | } else {
579 | webIdentity.getWebIdentity(domain).enabled = !webIdentity.getWebIdentity(domain).enabled;
580 | // Disable/enable toolbar-icon
581 | document.getElementById("fp-block-toolbar-button").setAttribute("fpblockActivated", webIdentity.getWebIdentity(domain).enabled);
582 | }
583 | } catch(e) {
584 | alert(e);
585 | }
586 | content.location.reload();
587 | },
588 |
589 | toggleToolbarButton : function(browser) {
590 | if (browser != null) {
591 | var domain = null;
592 | // Try to get the domain name
593 | try {
594 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
595 | domain = eTLDService.getBaseDomain(browser.currentURI).toLowerCase();
596 | } catch(e) {
597 | domain = 'localhost';
598 | }
599 | // Try to disable/enable toolbar-icon
600 | try {
601 | // Private browsing mode
602 | if (browser.contentWindow && PrivateBrowsingUtils.isWindowPrivate(browser.contentWindow)) {
603 | document.getElementById("fp-block-toolbar-button").setAttribute("fpblockActivated", privateWebIdentity.getPrivateWebIdentity(domain).enabled);
604 | // Normal browsing mode
605 | } else {
606 | document.getElementById("fp-block-toolbar-button").setAttribute("fpblockActivated", webIdentity.getWebIdentity(domain).enabled);
607 | }
608 | } catch(e) {
609 | document.getElementById("fp-block-toolbar-button").setAttribute("fpblockActivated", true);
610 | }
611 | }
612 | },
613 |
614 | detectionListener : function(event) {
615 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
616 | var attribute = event.target.getAttribute("attribute").split(":");
617 | var dtn = detection.getDetection(attribute[0]);
618 | if (dtn == null) {
619 | var attributes = [];
620 | var canvas = {detected : false, colors: 0, width : 0, height: 0, format : null}
621 | if (attribute[1] == 'App Code Name' ||
622 | attribute[1] == 'App Name' ||
623 | attribute[1] == 'App Version' ||
624 | attribute[1] == 'Language' ||
625 | attribute[1] == 'OS CPU' ||
626 | attribute[1] == 'Platform' ||
627 | attribute[1] == 'Product' ||
628 | attribute[1] == 'User-Agent' ||
629 | attribute[1] == 'Vendor' ||
630 | attribute[1] == 'CPU Class' ||
631 | attribute[1] == 'System Language' ||
632 | attribute[1] == 'User Language' ||
633 | attribute[1] == 'Screen Height' ||
634 | attribute[1] == 'Screen Width' ||
635 | attribute[1] == 'Color Depth' ||
636 | attribute[1] == 'Available Height' ||
637 | attribute[1] == 'Available Width' ||
638 | attribute[1] == 'Pixel Depth' ||
639 | attribute[1] == 'Timezone') {
640 | attributes.push({name : attribute[1], action : "spoof"});
641 | } else {
642 | if (attribute[1].indexOf("Canvas To Data URL") > -1) {
643 | var properties = attribute[1].split(" - ")[1].split(", ");
644 | canvas.colors = properties[0];
645 | canvas.width = properties[1];
646 | canvas.height = properties[2];
647 | canvas.format = properties[3];
648 | if (properties[4] != "null") canvas.data = properties[4];
649 | attributes.push({name : "Canvas To Data URL", action : "block"});
650 | } else {
651 | attributes.push({name : attribute[1], action : "block"});
652 | }
653 | }
654 | detection.addDetection(attribute[0], attributes, false, canvas);
655 | } else {
656 | var attributes = dtn.attributes;
657 | for (var i = 0; i < attributes.length; i++) {
658 | if (attribute[1].indexOf(attributes[i].name) > -1) {
659 | if (!dtn.notified && preferences.getBoolPref('notifydetections')) {
660 | fpBlock.detectionNotification(attribute[0]);
661 | }
662 | return;
663 | }
664 | }
665 | if (attribute[1] == 'App Code Name' ||
666 | attribute[1] == 'App Name' ||
667 | attribute[1] == 'App Version' ||
668 | attribute[1] == 'Language' ||
669 | attribute[1] == 'OS CPU' ||
670 | attribute[1] == 'Platform' ||
671 | attribute[1] == 'Product' ||
672 | attribute[1] == 'User-Agent' ||
673 | attribute[1] == 'Vendor' ||
674 | attribute[1] == 'CPU Class' ||
675 | attribute[1] == 'System Language' ||
676 | attribute[1] == 'User Language' ||
677 | attribute[1] == 'Screen Height' ||
678 | attribute[1] == 'Screen Width' ||
679 | attribute[1] == 'Color Depth' ||
680 | attribute[1] == 'Available Height' ||
681 | attribute[1] == 'Available Width' ||
682 | attribute[1] == 'Pixel Depth' ||
683 | attribute[1] == 'Timezone') {
684 | attributes.push({name : attribute[1], action : "spoof"});
685 | } else {
686 | if (attribute[1].indexOf("Canvas To Data URL") > -1) {
687 | var properties = attribute[1].split(" - ")[1].split(", ");
688 | dtn.canvas.colors = properties[0];
689 | dtn.canvas.width = properties[1];
690 | dtn.canvas.height = properties[2];
691 | dtn.canvas.format = properties[3];
692 | if (properties[4] != "null") dtn.canvas.data = properties[4];
693 | attributes.push({name : "Canvas To Data URL", action : "block"});
694 | } else {
695 | attributes.push({name : attribute[1], action : "block"});
696 | }
697 | }
698 | dtn.notified = false;
699 | // Canvas Fingerprinting detection algorithm
700 | // -----------------------------------------
701 | if (!dtn.canvas.detected) {
702 | // 1. There should be both ToDataURL and fillText (or strokeText)
703 | // method calls and both calls should come from the same URL.
704 | for (var i = 0; i < dtn.attributes.length; i++) {
705 | if (dtn.attributes[i].name == 'Canvas To Data URL') {
706 | for (var j = 0; j < dtn.attributes.length; j++) {
707 | if (dtn.attributes[j].name == 'Canvas Fill Text' || dtn.attributes[j].name == 'Canvas Stroke Text') {
708 | // 2. The canvas image(s) read by the script should contain more than one color and
709 | // its(their) aggregate size should be greater than 16x16 pixels.
710 | if (dtn.canvas.colors > 1 && dtn.canvas.width > 16 && dtn.canvas.height > 16) {
711 | // 3. The image should not be requested in a lossy compression format such as JPEG.
712 | if (dtn.canvas.format == "null") {
713 | dtn.canvas.detected = true;
714 | var params = {url : attribute[0]};
715 | window.openDialog("chrome://fpblock/content/canvasFingerprinting.xul", "", "chrome, centerscreen, modal", params).focus();
716 | }
717 | }
718 | }
719 | }
720 | }
721 | }
722 | }
723 | }
724 | if (preferences.getBoolPref('notifydetections')) {
725 | fpBlock.detectionNotification(attribute[0]);
726 | }
727 | },
728 |
729 | detectionNotification : function(url) {
730 | var attributes = detection.getDetection(url).attributes;
731 | var attributeNames = [];
732 | for (var i = 0; i < attributes.length; i++) {
733 | attributeNames.push(attributes[i].name);
734 | }
735 | var message = "FP-Block prevented "+url+" from reading the following attributes: "+attributeNames.join(", ");
736 | var notificationBox = gBrowser.getNotificationBox();
737 | var notification = notificationBox.getNotificationWithValue('fingerprinting-blocked');
738 | if (notification) {
739 | notification.label = message;
740 | } else {
741 | var buttons = [{
742 | label: 'Allow',
743 | accessKey: 'A',
744 | callback: function() {
745 | var params = {url : url};
746 | window.openDialog("chrome://fpblock/content/webidentities.xul", "", "chrome, titlebar, toolbar, centerscreen, dialog=no, modal, resizable=yes", params).focus();
747 | detection.getDetection(url).notified = true;
748 | }
749 | },
750 | {
751 | label: 'Keep blocking',
752 | accessKey: 'B',
753 | callback: function() {
754 | detection.getDetection(url).notified = true;
755 | }
756 | }];
757 | const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
758 | notificationBox.appendNotification(message, 'fingerprinting-blocked', 'chrome://browser/skin/Info.png', priority, buttons);
759 | }
760 | },
761 |
762 | shutdown : function() {
763 | // Clear private web identities
764 | privateWebIdentity.clearPrivateWebIdentities();
765 | // Save detections
766 | detection.saveDetections();
767 | // Save web identities
768 | webIdentity.saveWebIdentities();
769 | // Remove tab event listeners
770 | var container = gBrowser.tabContainer;
771 | container.removeEventListener("TabOpen", fpBlock.tabOpen, false);
772 | container.removeEventListener("TabSelect", fpBlock.tabSelect, false);
773 | gBrowser.removeEventListener("load", fpBlock.pageLoad, true);
774 | // Unregister the HTTP Request Observer
775 | httpRequestObserver.unregister();
776 | // Unregister the third-party cookies preferences observer
777 | preferencesThirdPartiesObserver.unregister();
778 | // Unregister the DNT header preferences observer
779 | preferencesDNTObserver.unregister();
780 | // Unregister the automatic connections preferences observer
781 | preferencesAutomaticConnectionsObserver.unregister();
782 | }
783 | };
784 | }();
785 |
786 | window.addEventListener("load", fpBlock.init, false);
787 | window.addEventListener("unload", fpBlock.shutdown, false);
788 |
789 | var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
790 | mainWindow.document.addEventListener("DetectionEvent", function(event) { fpBlock.detectionListener(event); }, false, true);
791 |
792 | var addonListener = {
793 | onUninstalling: function(addon, restart) {
794 | if (addon.id == "fpblock@fingerprint.christoftorres.com") {
795 | // Reset Firefox preferences
796 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("network.cookie.").clearPref("cookieBehavior");
797 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("privacy.donottrackheader.").clearPref("enabled");
798 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("network.http.").clearPref("speculative-parallel-limit");
799 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("network.dns.").clearPref("disablePrefetch");
800 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("network.").clearPref("prefetch-next");
801 | // Remove FP-Block preferences
802 | Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("extensions.").deleteBranch("fpblock");
803 | }
804 | }
805 | }
806 |
807 | try {
808 | Components.utils.import("resource://gre/modules/AddonManager.jsm");
809 | AddonManager.addAddonListener(addonListener);
810 | } catch (e) {
811 | alert(e);
812 | }
813 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/thirdparties.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 03.02.2015 */
5 | /****************************************************************/
6 |
7 | Components.utils.import("resource://modules/webIdentity.jsm");
8 |
9 | // Called once when the dialog displays
10 | function onLoad() {
11 | // If the window has any parameters then...
12 | if (window.arguments != null) {
13 | // Get the web identity based on the domain parameter of the window
14 | var webID = webIdentity.getWebIdentity(window.arguments[0].domain);
15 | // Set the domain name
16 | document.getElementById('domain-name').value = webID.domain;
17 | // Set the number of third-parties
18 | document.getElementById('thirdparties-number').value = webID.thirdparties.length;
19 | // Get the richlistbox
20 | var richlistbox = document.getElementById('richlistbox-third-parties');
21 | // Add all third-parties to the richlistbox
22 | var thirdparties = webID.thirdparties;
23 | for (var index in thirdparties) {
24 | // Create a new richlistitem
25 | var richlistitem = document.createElement('richlistitem');
26 | // Create a new checkbox
27 | var checkbox = document.createElement('checkbox');
28 | // Add the label of the current third-party to the checkbox
29 | checkbox.setAttribute('label', thirdparties[index].name);
30 | // Set the checkbox as checked if the current third-party is enabled
31 | checkbox.setAttribute('checked', thirdparties[index].enabled);
32 | // Append the checkbox to the richlistitem
33 | richlistitem.appendChild(checkbox);
34 | // Append the richlistitem to the richlistbox
35 | richlistbox.appendChild(richlistitem);
36 | }
37 | }
38 | }
39 |
40 | // Called when the user clicks on the 'OK' button
41 | function accept() {
42 | // Get the domain name
43 | var domain = document.getElementById('domain-name').value;
44 | // Get all the checkboxes
45 | var checkboxes = document.getElementsByTagName('checkbox');
46 | // Get all third-parties
47 | var thirdparties = webIdentity.getWebIdentity(domain).thirdparties;
48 | // For each third-party...
49 | for (var index in thirdparties) {
50 | // ...set the third-party as enabled/disabled if the coresponding checkbox was checked/unchecked
51 | thirdparties[index].enabled = checkboxes[index].getAttribute('checked');
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/thirdparties.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/webidentities.css:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 06.06.2014 */
5 | /****************************************************************/
6 |
7 | treechildren::-moz-tree-checkbox {
8 | /* unchecked checkbox treecells. This style MUST come before treechildren::-moz-tree-checkbox(checked) otherwise it won't take effect. */
9 | list-style-image: url("chrome://fpblock/skin/block.png");
10 | }
11 |
12 | treechildren::-moz-tree-checkbox(checked) {
13 | /* css for checked cells. cbox-check.gif isn't available in Firefox 1, 2, and 3 on Mac OS X, so you should specify a URL to an image
14 | in your extension or elsewhere. */
15 | list-style-image: url("chrome://fpblock/skin/allow.png");
16 | }
17 |
18 | #number-of-web-identities {
19 | padding: 6px 0px 0px 100px;
20 | }
21 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/webidentities.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 31.08.2015 */
5 | /****************************************************************/
6 |
7 | Components.utils.import("resource://modules/webIdentity.jsm");
8 | Components.utils.import("resource://modules/detection.jsm");
9 | Components.utils.import("resource://modules/randomFingerprintGenerator.jsm");
10 |
11 | var Cc = Components.classes;
12 | var Ci = Components.interfaces;
13 |
14 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
15 |
16 | var nrOfWebIdentities;
17 |
18 |
19 | // This is just a test funtion in order to measure how much time it takes to generate (and reach) the web identities limit
20 | /*
21 | function generateWebIdentities() {
22 | clearWebIdentities();
23 | var start = new Date().getTime();
24 | for (var i = 1; i <= preferences.getIntPref('webidentitieslimit'); i++) {
25 | var socialplugins = {facebook : undefined, twitter : undefined , googleplus : undefined, linkedin : undefined, tumblr : undefined, pinterest : undefined};
26 | var browserplugins = {flash : false, silverlight : false, vlc : false, quicktime : false, other : false};
27 | var generatedFingerprint = randomFingerprintGenerator.generateAndCheckUniqueness(webIdentity.getWebIdentities());
28 | webIdentity.addWebIdentity('test'+i+'.com', generatedFingerprint.fingerprint, generatedFingerprint.profile, generatedFingerprint.hash, generatedFingerprint.usage, socialplugins, browserplugins);
29 | document.getElementById("number-of-generations").innerHTML = webIdentity.getWebIdentities().length+"/"+preferences.getIntPref('webidentitieslimit');
30 | }
31 | var stop = new Date().getTime();
32 | var elapsed = stop - start;
33 | document.getElementById("number-of-generations").innerHTML += " " + elapsed + "ms";
34 | }
35 | */
36 |
37 | // Called once when the dialog displays
38 | function onLoad() {
39 | // Get the tree
40 | var tree = document.getElementById("webIdentitiesTree");
41 | // Get the children of the tree
42 | var treeChildren = document.getElementById("webIdentitiesTreeChildren");
43 | // Sort the web identities alphabeticaly prior to the domain
44 | var webIDs = webIdentity.getWebIdentities().sort(function compare(a,b) {
45 | if (a.domain < b.domain)
46 | return -1;
47 | if (a.domain > b.domain)
48 | return 1;
49 | return 0;
50 | });
51 | nrOfWebIdentities = 0;
52 | // For each web identity...
53 | for (var i = 0; i < webIDs.length; i++) {
54 | try {
55 | var attributes = detection.getDetection(webIDs[i].domain).attributes;
56 | var item = document.createElement('treeitem');
57 | item.setAttribute('container', 'true');
58 | if (window.arguments != null && window.arguments[0].url.indexOf(webIDs[i].domain) != -1) {
59 | tree.view.selection.select(i);
60 | item.setAttribute('open', 'true');
61 | }
62 | var row = document.createElement('treerow');
63 | var cell = document.createElement('treecell');
64 | // Add the domain name to the tree
65 | cell.setAttribute('label', webIDs[i].domain);
66 | row.appendChild(cell);
67 | item.appendChild(row);
68 | var children = document.createElement('treechildren');
69 | // For each attribute of the web identity...
70 | for (var j = 0; j < attributes.length; j++) {
71 | var innerItem = document.createElement('treeitem');
72 | var innerRow = document.createElement('treerow');
73 | var innerCell = document.createElement('treecell');
74 | // Add the attribute name to the tree
75 | innerCell.setAttribute('label', attributes[j].name);
76 | innerRow.appendChild(innerCell);
77 | innerCell = document.createElement('treecell');
78 | // Add the attribute value to the tree
79 | if (attributes[j].name == 'App Code Name') {
80 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.appCodeName);
81 | } else
82 | if (attributes[j].name == 'App Name') {
83 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.appName);
84 | } else
85 | if (attributes[j].name == 'App Version') {
86 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.appVersion);
87 | } else
88 | if (attributes[j].name == 'Language') {
89 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.language);
90 | } else
91 | if (attributes[j].name == 'OS CPU') {
92 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.oscpu);
93 | } else
94 | if (attributes[j].name == 'Platform') {
95 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.platform);
96 | } else
97 | if (attributes[j].name == 'Product') {
98 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.product);
99 | } else
100 | if (attributes[j].name == 'User-Agent') {
101 | innerCell.setAttribute('label', webIDs[i].fingerprint.useragent);
102 | } else
103 | if (attributes[j].name == 'Vendor') {
104 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.vendor);
105 | } else
106 | if (attributes[j].name == 'CPU Class') {
107 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.cpuClass);
108 | } else
109 | if (attributes[j].name == 'System Language') {
110 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.systemLanguage);
111 | } else
112 | if (attributes[j].name == 'User Language') {
113 | innerCell.setAttribute('label', webIDs[i].fingerprint.navigator.userLanguage);
114 | } else
115 | if (attributes[j].name == 'Screen Height') {
116 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.height);
117 | } else
118 | if (attributes[j].name == 'Screen Width') {
119 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.width);
120 | } else
121 | if (attributes[j].name == 'Color Depth') {
122 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.colorDepth);
123 | } else
124 | if (attributes[j].name == 'Available Height') {
125 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.availHeight);
126 | } else
127 | if (attributes[j].name == 'Available Width') {
128 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.availWidth);
129 | } else
130 | if (attributes[j].name == 'Pixel Depth') {
131 | innerCell.setAttribute('label', webIDs[i].fingerprint.screen.pixelDepth);
132 | } else
133 | if (attributes[j].name == 'Timezone') {
134 | innerCell.setAttribute('label', webIDs[i].fingerprint.date.timezoneOffset);
135 | }
136 | innerRow.appendChild(innerCell);
137 | innerCell = document.createElement('treecell');
138 | // Add the attribute action to the tree
139 | if (attributes[j].name != 'Plugins' && attributes[j].name != 'Mime Types') {
140 | if (attributes[j].action == 'spoof') {
141 | innerCell.setAttribute('src', 'chrome://fpblock/skin/spoof.png');
142 | innerCell.setAttribute('label', ' Spoof');
143 | } else
144 | if (attributes[j].action == 'block') {
145 | innerCell.setAttribute('src', 'chrome://fpblock/skin/block.png');
146 | innerCell.setAttribute('label', ' Block');
147 | } else {
148 | innerCell.setAttribute('src', 'chrome://fpblock/skin/allow.png');
149 | innerCell.setAttribute('label', ' Allow');
150 | }
151 | }
152 | innerRow.appendChild(innerCell);
153 | innerItem.appendChild(innerRow);
154 | children.appendChild(innerItem);
155 | }
156 | item.appendChild(children);
157 | treeChildren.appendChild(item);
158 | nrOfWebIdentities++;
159 | } catch(e) {
160 |
161 | }
162 | }
163 | updateNrOfWebIdentities();
164 | }
165 |
166 | function clearWebIdentities() {
167 | // Delete all the detected attributes
168 | detection.clearDetections();
169 | // Delete all the created web identities
170 | webIdentity.clearWebIdentities();
171 | // Update the tree
172 | var treeChildren = document.getElementById("webIdentitiesTreeChildren");
173 | while (treeChildren.lastChild) {
174 | treeChildren.removeChild(treeChildren.lastChild);
175 | }
176 | // Update the number of web identities
177 | nrOfWebIdentities = 0;
178 | updateNrOfWebIdentities();
179 | }
180 |
181 | function showPopup() {
182 | // Get the tree
183 | var tree = document.getElementById("webIdentitiesTree");
184 | // Get the name of the selected web identity or attribute
185 | var cellText = tree.view.getCellText(tree.currentIndex, tree.columns.getColumnAt(0));
186 | // Set the context menu for Plugins or Mime Types
187 | if (cellText == 'Plugins' || cellText == 'Mime Types') {
188 | document.getElementById('third-parties').hidden = true;
189 | document.getElementById('edit').hidden = true;
190 | document.getElementById('delete').label = "Delete Attribute";
191 | document.getElementById('regenerate').hidden = true;
192 | // Debugging mode
193 | document.getElementById('hash').hidden = true;
194 | document.getElementById('usage-amount').hidden = true;
195 | document.getElementById('usage-date').hidden = true;
196 | } else
197 | // Set the context menu for a web identity
198 | if (cellText.indexOf('.') != -1 || cellText == 'localhost') {
199 | document.getElementById('third-parties').hidden = false;
200 | document.getElementById('edit').hidden = true;
201 | document.getElementById('delete').label = "Delete Web Identity";
202 | document.getElementById('regenerate').hidden = false;
203 | document.getElementById('regenerate').label = "Regenerate Web Identity";
204 | // Debugging mode
205 | if (preferences.getBoolPref('debuggingmode')) {
206 | document.getElementById('hash').hidden = false;
207 | document.getElementById('hash').label = "Hash: "+webIdentity.getWebIdentity(cellText).hash;
208 | document.getElementById('usage-amount').hidden = false;
209 | document.getElementById('usage-amount').label = "Usage amount: "+webIdentity.getWebIdentity(cellText).usage.amount;
210 | document.getElementById('usage-date').hidden = false;
211 | document.getElementById('usage-date').label = "Usage date: "+new Date(webIdentity.getWebIdentity(cellText).usage.date).toUTCString();
212 | } else {
213 | document.getElementById('hash').hidden = true;
214 | document.getElementById('usage-amount').hidden = true;
215 | document.getElementById('usage-date').hidden = true;
216 | }
217 | // Set the context menu for the remaining attributes
218 | } else {
219 | document.getElementById('third-parties').hidden = true;
220 | document.getElementById('edit').hidden = false;
221 | document.getElementById('delete').label = "Delete Attribute";
222 | if (cellText == 'App Code Name' ||
223 | cellText == 'App Name' ||
224 | cellText == 'App Version' ||
225 | cellText == 'Language' ||
226 | cellText == 'OS CPU' ||
227 | cellText == 'Platform' ||
228 | cellText == 'Product' ||
229 | cellText == 'User-Agent' ||
230 | cellText == 'Vendor' ||
231 | cellText == 'CPU Class' ||
232 | cellText == 'System Language' ||
233 | cellText == 'User Language' ||
234 | cellText == 'Screen Height' ||
235 | cellText == 'Screen Width' ||
236 | cellText == 'Color Depth' ||
237 | cellText == 'Available Height' ||
238 | cellText == 'Available Width' ||
239 | cellText == 'Pixel Depth' ||
240 | cellText == 'Timezone') {
241 | document.getElementById('regenerate').hidden = false;
242 | document.getElementById('regenerate').label = "Regenerate Attribute";
243 | } else {
244 | document.getElementById('regenerate').hidden = true;
245 | }
246 | // Debugging mode
247 | document.getElementById('hash').hidden = true;
248 | document.getElementById('usage-amount').hidden = true;
249 | document.getElementById('usage-date').hidden = true;
250 | }
251 | }
252 |
253 | function viewThirdParties() {
254 | // Get the tree
255 | var tree = document.getElementById("webIdentitiesTree");
256 | // Get the selected index
257 | var currentIndex = tree.currentIndex;
258 | // Get the domain name of the selected index
259 | var domain = tree.view.getCellText(currentIndex, tree.columns.getColumnAt(0));
260 | // Set the domain as a parameter for the third-parties window
261 | var params = {domain : domain};
262 | // Call the third-parties window
263 | window.openDialog("chrome://fpblock/content/thirdparties.xul", "", "chrome, titlebar, toolbar, centerscreen, dialog=no, modal, resizable=yes", params).focus();
264 | }
265 |
266 | function editAttribute() {
267 | // Get the tree
268 | var tree = document.getElementById("webIdentitiesTree");
269 | // Get the selected index
270 | var currentIndex = tree.currentIndex;
271 | // Get the attribute name
272 | var name = tree.view.getCellText(currentIndex, tree.columns.getColumnAt(0));
273 | // Get the domain name
274 | var url = tree.view.getCellText(tree.view.getParentIndex(currentIndex), tree.columns.getColumnAt(0));
275 | // Set the domain name and the attribute name as parameters for the edit attribute window
276 | var params = {url : url, name : name};
277 | // Call the edit attribute window
278 | window.openDialog("chrome://fpblock/content/attribute.xul", "", "chrome, titlebar, toolbar, centerscreen, dialog=no, modal, resizable=yes", params).focus();
279 | // Update the tree
280 | var webID = webIdentity.getWebIdentity(url);
281 | var attribute = detection.getAttribute(url, name);
282 | if (attribute.name == 'App Code Name') {
283 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.appCodeName);
284 | } else
285 | if (attribute.name == 'App Name') {
286 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.appName);
287 | } else
288 | if (attribute.name == 'App Version') {
289 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.appVersion);
290 | } else
291 | if (attribute.name == 'Language') {
292 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.language);
293 | } else
294 | if (attribute.name == 'OS CPU') {
295 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.oscpu);
296 | } else
297 | if (attribute.name == 'Platform') {
298 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.platform);
299 | } else
300 | if (attribute.name == 'Product') {
301 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.product);
302 | } else
303 | if (attribute.name == 'User-Agent') {
304 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.useragent);
305 | } else
306 | if (attribute.name == 'Vendor') {
307 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.vendor);
308 | } else
309 | if (attribute.name == 'CPU Class') {
310 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.cpuClass);
311 | } else
312 | if (attribute.name == 'System Language') {
313 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.systemLanguage);
314 | } else
315 | if (attribute.name == 'User Language') {
316 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.navigator.userLanguage);
317 | } else
318 | if (attribute.name == 'Screen Height') {
319 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.height);
320 | } else
321 | if (attribute.name == 'Screen Width') {
322 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.width);
323 | } else
324 | if (attribute.name == 'Color Depth') {
325 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.colorDepth);
326 | } else
327 | if (attribute.name == 'Available Height') {
328 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.availHeight);
329 | } else
330 | if (attribute.name == 'Available Width') {
331 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.availWidth);
332 | } else
333 | if (attribute.name == 'Pixel Depth') {
334 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.screen.pixelDepth);
335 | } else
336 | if (attribute.name == 'Timezone') {
337 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webID.fingerprint.date.timezoneOffset);
338 | }
339 | if (attribute.action == 'spoof') {
340 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('src', 'chrome://fpblock/skin/spoof.png');
341 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('label', ' Spoof');
342 | } else
343 | if (attribute.action == 'block') {
344 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('src', 'chrome://fpblock/skin/block.png');
345 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('label', ' Block');
346 | } else {
347 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('src', 'chrome://fpblock/skin/allow.png');
348 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[2].setAttribute('label', ' Allow');
349 | }
350 | }
351 |
352 | function deleteWebIdentityAttribute() {
353 | // Get the tree
354 | var tree = document.getElementById("webIdentitiesTree");
355 | // Get the selected index
356 | var currentIndex = tree.currentIndex;
357 | var cellText = tree.view.getCellText(currentIndex, tree.columns.getColumnAt(0));
358 | // Delete the selected web identity
359 | if (cellText.indexOf('.') != -1) {
360 | detection.deleteDetection(cellText);
361 | webIdentity.deleteWebIdentity(cellText);
362 | // Delete the selected attribute
363 | } else {
364 | var url = tree.view.getCellText(tree.view.getParentIndex(currentIndex), tree.columns.getColumnAt(0));
365 | detection.deleteAttribute(url, cellText);
366 | }
367 | // Update the tree
368 | tree.view.getItemAtIndex(currentIndex).parentNode.removeChild(tree.view.getItemAtIndex(currentIndex));
369 | // Update the number of web identities
370 | nrOfWebIdentities--;
371 | updateNrOfWebIdentities();
372 | }
373 |
374 | function regenerateWebIdentityAttribute() {
375 | // Get the tree
376 | var tree = document.getElementById("webIdentitiesTree");
377 | // Get the selected index
378 | var currentIndex = tree.currentIndex;
379 | var cellText = tree.view.getCellText(currentIndex, tree.columns.getColumnAt(0));
380 | // Regenerate the selected web identity
381 | if (cellText.indexOf('.') != -1) {
382 | var generatedFingerprint = randomFingerprintGenerator.generateAndCheckUniqueness(webIdentity.getWebIdentities());
383 | webIdentity.getWebIdentity(cellText).fingerprint = generatedFingerprint.fingerprint;
384 | webIdentity.getWebIdentity(cellText).profile = generatedFingerprint.profile;
385 | webIdentity.getWebIdentity(cellText).hash = generatedFingerprint.hash;
386 | webIdentity.getWebIdentity(cellText).usage = generatedFingerprint.usage;
387 | var attributes = tree.view.getItemAtIndex(currentIndex).getElementsByTagName("treeitem");
388 | for (var i = 0; i < attributes.length; i++) {
389 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'App Code Name') {
390 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.appCodeName);
391 | } else
392 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'App Name') {
393 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.appName);
394 | } else
395 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'App Version') {
396 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.appVersion);
397 | } else
398 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Language') {
399 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.language);
400 | } else
401 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'OS CPU') {
402 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.oscpu);
403 | } else
404 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Platform') {
405 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.platform);
406 | } else
407 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Product') {
408 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.product);
409 | } else
410 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'User-Agent') {
411 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.useragent);
412 | } else
413 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Vendor') {
414 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.vendor);
415 | } else
416 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'CPU Class') {
417 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.cpuClass);
418 | } else
419 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'System Language') {
420 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.systemLanguage);
421 | } else
422 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'User Language') {
423 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.navigator.userLanguage);
424 | } else
425 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Screen Height') {
426 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.height);
427 | } else
428 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Screen Width') {
429 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.width);
430 | } else
431 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Color Depth') {
432 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.colorDepth);
433 | } else
434 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Available Height') {
435 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.availHeight);
436 | } else
437 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Available Width') {
438 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.availWidth);
439 | } else
440 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Pixel Depth') {
441 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.screen.pixelDepth);
442 | } else
443 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Timezone') {
444 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(cellText).fingerprint.date.timezoneOffset);
445 | }
446 | }
447 | // Regenerate the selected attribute and update the tree accordingly
448 | } else {
449 | try {
450 | var domain = tree.view.getCellText(tree.view.getParentIndex(currentIndex), tree.columns.getColumnAt(0));
451 | if (cellText == 'App Code Name') {
452 | webIdentity.getWebIdentity(domain).fingerprint.navigator.appCodeName = randomFingerprintGenerator.generateAppCodeName(webIdentity.getWebIdentity(domain).profile);
453 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.appCodeName);
454 | } else
455 | if (cellText == 'App Name') {
456 | webIdentity.getWebIdentity(domain).fingerprint.navigator.appName = randomFingerprintGenerator.generateAppName(webIdentity.getWebIdentity(domain).profile);
457 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.appName);
458 | } else
459 | if (cellText == 'User-Agent' || cellText == 'App Version' || cellText == 'OS CPU' || cellText == 'Platform' || cellText == 'CPU Class') {
460 | var randomUserAgentAndNavigatiorObject = randomFingerprintGenerator.generateUserAgentAndNavigatorObject(webIdentity.getWebIdentity(domain).profile);
461 | webIdentity.getWebIdentity(domain).fingerprint.useragent = randomUserAgentAndNavigatiorObject.useragent;
462 | webIdentity.getWebIdentity(domain).fingerprint.navigator = randomUserAgentAndNavigatiorObject.navigatorObject;
463 | var attributes = tree.view.getItemAtIndex(currentIndex).parentNode.getElementsByTagName("treeitem");
464 | for (var i = 0; i < attributes.length; i++) {
465 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'User-Agent') {
466 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.useragent);
467 | } else
468 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'App Version') {
469 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.appVersion);
470 | } else
471 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'OS CPU') {
472 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.oscpu);
473 | } else
474 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Platform') {
475 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.platform);
476 | } else
477 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'CPU Class') {
478 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.cpuClass);
479 | } else
480 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Language') {
481 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.language);
482 | } else
483 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'System Language') {
484 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.systemLanguage);
485 | } else
486 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'User Language') {
487 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.userLanguage);
488 | }
489 | }
490 | } else
491 | if (cellText == 'Language') {
492 | webIdentity.getWebIdentity(domain).fingerprint.navigator.language = randomFingerprintGenerator.generateLanguage(webIdentity.getWebIdentity(domain).profile);
493 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.language);
494 | } else
495 | if (cellText == 'System Language') {
496 | webIdentity.getWebIdentity(domain).fingerprint.navigator.systemLanguage = randomFingerprintGenerator.generateLanguage(webIdentity.getWebIdentity(domain).profile);
497 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.systemLanguage);
498 | } else
499 | if (cellText == 'User Language') {
500 | webIdentity.getWebIdentity(domain).fingerprint.navigator.userLanguage = randomFingerprintGenerator.generateLanguage(webIdentity.getWebIdentity(domain).profile);
501 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.userLanguage);
502 | } else
503 | if (cellText == 'Product') {
504 | webIdentity.getWebIdentity(domain).fingerprint.navigator.product = randomFingerprintGenerator.generateProduct(webIdentity.getWebIdentity(domain).profile);
505 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.product);
506 | } else
507 | if (cellText == 'Vendor') {
508 | webIdentity.getWebIdentity(domain).fingerprint.navigator.vendor = randomFingerprintGenerator.generateVendor(webIdentity.getWebIdentity(domain).profile);
509 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.navigator.vendor);
510 | } else
511 | if (cellText == 'Screen Height' || cellText == 'Screen Width' || cellText == 'Available Height' || cellText == 'Available Width') {
512 | var randomScreenObject = randomFingerprintGenerator.generateScreenObject(webIdentity.getWebIdentity(domain).profile);
513 | webIdentity.getWebIdentity(domain).fingerprint.screen.height = randomScreenObject.height;
514 | webIdentity.getWebIdentity(domain).fingerprint.screen.width = randomScreenObject.width;
515 | webIdentity.getWebIdentity(domain).fingerprint.screen.availHeight = randomScreenObject.availHeight;
516 | webIdentity.getWebIdentity(domain).fingerprint.screen.availWidth = randomScreenObject.availWidth;
517 | var attributes = tree.view.getItemAtIndex(currentIndex).parentNode.getElementsByTagName("treeitem");
518 | for (var i = 0; i < attributes.length; i++) {
519 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Screen Height') {
520 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.height);
521 | } else
522 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Screen Width') {
523 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.width);
524 | } else
525 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Available Height') {
526 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.availHeight);
527 | } else
528 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Available Width') {
529 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.availWidth);
530 | }
531 | }
532 | } else
533 | if (cellText == 'Color Depth' || cellText == 'Pixel Depth') {
534 | var randomScreenObject = randomFingerprintGenerator.generateScreenObject(webIdentity.getWebIdentity(domain).profile);
535 | webIdentity.getWebIdentity(domain).fingerprint.screen.colorDepth = randomScreenObject.colorDepth;
536 | webIdentity.getWebIdentity(domain).fingerprint.screen.pixelDepth = randomScreenObject.pixelDepth;
537 | var attributes = tree.view.getItemAtIndex(currentIndex).parentNode.getElementsByTagName("treeitem");
538 | for (var i = 0; i < attributes.length; i++) {
539 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Color Depth') {
540 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.colorDepth);
541 | } else
542 | if (attributes[i].firstChild.childNodes[0].getAttribute('label') == 'Pixel Depth') {
543 | attributes[i].firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.screen.pixelDepth);
544 | }
545 | }
546 | } else
547 | if (cellText == 'Timezone') {
548 | webIdentity.getWebIdentity(domain).fingerprint.date = randomFingerprintGenerator.generateTimezone(webIdentity.getWebIdentity(domain).profile);
549 | tree.view.getItemAtIndex(currentIndex).firstChild.childNodes[1].setAttribute('label', webIdentity.getWebIdentity(domain).fingerprint.date.timezoneOffset);
550 | }
551 | webIdentity.getWebIdentity(domain).hash = randomFingerprintGenerator.generateHash(webIdentity.getWebIdentity(domain).fingerprint);
552 | } catch(e) {
553 | alert(e);
554 | }
555 | }
556 | }
557 |
558 | function updateNrOfWebIdentities() {
559 | while (document.getElementById("number-of-web-identities").lastChild) {
560 | document.getElementById("number-of-web-identities").removeChild(document.getElementById("number-of-web-identities").lastChild);
561 | }
562 | document.getElementById("number-of-web-identities").appendChild(document.createTextNode("Number of web identities: "+nrOfWebIdentities));
563 | if (preferences.getBoolPref('debuggingmode')) {
564 | var span = document.createElement("SPAN");
565 | span.setAttribute('style', 'color:gray');
566 | span.appendChild(document.createTextNode("/"+webIdentity.getWebIdentities().length));
567 | document.getElementById("number-of-web-identities").appendChild(span);
568 | }
569 | }
570 |
--------------------------------------------------------------------------------
/Plugin/chrome/content/webidentities.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Plugin/defaults/preferences/defaults.js:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 21.08.2015 */
5 | /****************************************************************/
6 |
7 | // First run
8 | pref("extensions.fpblock.firstrun", true);
9 | // Genreal preferences
10 | pref("extensions.fpblock.notifydetections", true);
11 | // HTTP preferences
12 | pref("extensions.fpblock.blockthirdparties", true);
13 | //pref("extensions.fpblock.deletereferer", true);
14 | pref("extensions.fpblock.dntheader", true);
15 | pref("extensions.fpblock.deleteetags", true);
16 | // JavaScript preferences
17 | pref("extensions.fpblock.autoblocksocial", false);
18 | pref("extensions.fpblock.autoblockplugins", true);
19 | // Firefox automatic connections preferences
20 | pref("extensions.fpblock.autoblockconnections", true);
21 | // Data storage
22 | pref("extensions.fpblock.webidentities", "[]");
23 | pref("extensions.fpblock.detections", "[]");
24 | // Limit of generated unique web identities
25 | pref("extensions.fpblock.webidentitieslimit", 1024);
26 | // Date of last time that profiles were fetched
27 | pref("extensions.fpblock.latestfetch", "");
28 | // Debugging mode
29 | pref("extensions.fpblock.debuggingmode", false);
--------------------------------------------------------------------------------
/Plugin/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/icon.png
--------------------------------------------------------------------------------
/Plugin/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 | fpblock@fingerprint.christoftorres.com
11 | 1.0.2
12 | 2
13 | true
14 |
15 | chrome://fpblock/content/options.xul
16 |
17 |
18 |
19 | FP-Block
20 | FP-Block helps you to preserve privacy on the web with respect to browser fingerptinting. FP-Block aims to keep your web identities seperate through creating unique web identites for each website you visit. It allows you to block social plugins and to block individual browser plugins. Furthermore, it allows you to detect third-parties and to block, allow or spoof JavaScript attributes that a website tries to read. Please note that FP-Block is solely a proof-of-concept.
21 | Christof Torres
22 | http://www.open.ou.nl/hjo/software/fp-block/
23 | chrome://fpblock/skin/icon32.png
24 | chrome://fpblock/skin/icon64.png
25 |
26 |
27 |
28 |
29 |
30 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
31 | 4.0
32 | 16.*
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Plugin/locale/en-US/translations.dtd:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Plugin/modules/detection.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 16.09.2014 */
5 | /****************************************************************/
6 |
7 | var EXPORTED_SYMBOLS = ["detection"];
8 |
9 | var Cc = Components.classes;
10 | var Ci = Components.interfaces;
11 |
12 | var detection = {
13 | detections : [],
14 |
15 | loadDetections : function() {
16 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
17 | this.detections = JSON.parse(preferences.getCharPref('detections'));
18 | },
19 |
20 | saveDetections : function() {
21 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
22 | preferences.setCharPref('detections', JSON.stringify(this.detections));
23 | },
24 |
25 | clearDetections : function() {
26 | this.detections = [];
27 | },
28 |
29 | deleteDetection : function(url) {
30 | for (var i = 0; i < this.detections.length; i++) {
31 | if (this.detections[i].url.indexOf(url) != -1) {
32 | this.detections.splice(i,1);
33 | return;
34 | }
35 | }
36 | },
37 |
38 | deleteAttribute : function(url, name) {
39 | for (var i = 0; i < this.detections.length; i++) {
40 | if (this.detections[i].url.indexOf(url) != -1) {
41 | for (var j = 0; j < this.detections[i].attributes.length; j++) {
42 | if (this.detections[i].attributes[j].name.indexOf(name) != -1) {
43 | this.detections[i].attributes.splice(j,1);
44 | return;
45 | }
46 | }
47 | }
48 | }
49 | },
50 |
51 | addDetection : function(url, attributes, notified, canvas) {
52 | this.detections.push({url : url, attributes : attributes, notified : notified, canvas : canvas});
53 | },
54 |
55 | getDetection : function(url) {
56 | for (var i = 0; i < this.detections.length; i++) {
57 | if (this.detections[i].url.indexOf(url) != -1) {
58 | return this.detections[i];
59 | }
60 | }
61 | return null;
62 | },
63 |
64 | getAttribute : function(url, name) {
65 | for (var i = 0; i < this.detections.length; i++) {
66 | if (this.detections[i].url.indexOf(url) != -1) {
67 | for (var j = 0; j < this.detections[i].attributes.length; j++) {
68 | if (this.detections[i].attributes[j].name.indexOf(name) != -1) {
69 | return this.detections[i].attributes[j];
70 | }
71 | }
72 | }
73 | }
74 | return null;
75 | },
76 |
77 | getAllDetections : function() {
78 | return this.detections;
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/Plugin/modules/httpRequestObserver.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 15.04.2015 */
5 | /****************************************************************/
6 |
7 | var EXPORTED_SYMBOLS = ["httpRequestObserver"];
8 |
9 | Components.utils.import("resource://lib/webIdentity.jsm");
10 | Components.utils.import("resource://lib/detection.jsm");
11 | Components.utils.import("resource://lib/randomFingerprintGenerator.jsm");
12 | Components.utils.import("resource://lib/responseListener.jsm");
13 |
14 | Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
15 |
16 | var Cc = Components.classes;
17 | var Ci = Components.interfaces;
18 |
19 | var httpRequestObserver = {
20 | observe : function(subject, topic, data) {
21 | // On HTTP request
22 | if (topic == "http-on-modify-request") {
23 | try {
24 | // Get the HTTP channel of the current request
25 | var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
26 |
27 | // Get the preferences and the effective TLD service
28 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
29 | var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
30 |
31 | // Try to get the requesting domain
32 | var requestDomain = null;
33 | try {
34 | requestDomain = eTLDService.getBaseDomain(httpChannel.originalURI).toLowerCase();
35 | } catch(e) {
36 | requestDomain = 'localhost';
37 | }
38 |
39 | // Try to get the DOM window
40 | var DOMWindow;
41 | try {
42 | // Try to get the current request's DOM window ...
43 | DOMWindow = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
44 | } catch(e) {
45 | // If this happens, then this means that the current request has no DOM window, because maybe it was the very first
46 | // request or it was initiated by an external party such as AJAX, Flash, Silverlight, etc.
47 | DOMWindow = null;
48 | }
49 |
50 | // Try to get the referring domain
51 | var referrerDomain = null;
52 | try {
53 | if (DOMWindow) {
54 | var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
55 | var uri = ioService.newURI(DOMWindow.top.document.URL, null, null);
56 | referrerDomain = eTLDService.getBaseDomain(uri).toLowerCase();
57 | } else {
58 | referrerDomain = eTLDService.getBaseDomain(httpChannel.referrer).toLowerCase();
59 | }
60 | } catch(e) {
61 | referrerDomain = 'localhost';
62 | }
63 |
64 | // Try to get the web identitiy for the referring domain
65 | var webID = null;
66 | try {
67 | // Private browsing mode
68 | if (DOMWindow && PrivateBrowsingUtils.isWindowPrivate(DOMWindow)) {
69 | webID = privateWebIdentity.getPrivateWebIdentity(referrerDomain);
70 | // Normal browsing mode
71 | } else {
72 | webID = webIdentity.getWebIdentity(referrerDomain);
73 | }
74 | } catch(e) {
75 | Components.utils.reportError(e);
76 | }
77 |
78 | // Create a new web identity if the web identity is not present
79 | if (!webID) {
80 | // Create a new social plugins object for the new web identity
81 | var socialplugins = {facebook : undefined, twitter : undefined , googleplus : undefined, linkedin : undefined, tumblr : undefined, pinterest : undefined};
82 | // Create a new browser plugins object for the new web identity
83 | var browserplugins = null;
84 | if (preferences.getBoolPref('autoblockplugins')) {
85 | browserplugins = {flash : false, silverlight : false, vlc : false, quicktime : false, other : false};
86 | } else {
87 | browserplugins = {flash : true, silverlight : true, vlc : true, quicktime : true, other : true};
88 | }
89 | // Create a new fingerprint for the new web identity
90 | try {
91 | // Private browsing mode
92 | if (DOMWindow && PrivateBrowsingUtils.isWindowPrivate(DOMWindow)) {
93 | var generatedFingerprint = randomFingerprintGenerator.generateAndCheckUniqueness(privateWebIdentity.getPrivateWebIdentities());
94 | privateWebIdentity.addPrivateWebIdentity(referrerDomain, generatedFingerprint.fingerprint, generatedFingerprint.profile, generatedFingerprint.hash, generatedFingerprint.usage, socialplugins, browserplugins);
95 | webID = privateWebIdentity.getPrivateWebIdentity(referrerDomain);
96 | // Normal browsing mode
97 | } else {
98 | var generatedFingerprint = randomFingerprintGenerator.generateAndCheckUniqueness(webIdentity.getWebIdentities());
99 | webIdentity.addWebIdentity(referrerDomain, generatedFingerprint.fingerprint, generatedFingerprint.profile, generatedFingerprint.hash, generatedFingerprint.usage, socialplugins, browserplugins);
100 | webID = webIdentity.getWebIdentity(referrerDomain);
101 | }
102 | } catch(e) {
103 | Components.utils.reportError(e);
104 | }
105 | }
106 |
107 | if (webID && webID.enabled) {
108 |
109 | var previousDate = new Date(webID.usage.date);
110 | var currentDate = new Date();
111 | // Increment usage amount if it's not the same day
112 | if (previousDate.getFullYear != currentDate.getFullYear || previousDate.getMonth != currentDate.getMonth || previousDate.getDate != currentDate.getDate) {
113 | webID.usage.amount++;
114 | }
115 | // Set current date
116 | webID.usage.date = currentDate;
117 |
118 | if (!detection.getAttribute(referrerDomain, 'User-Agent') || detection.getAttribute(referrerDomain, 'User-Agent').action == 'spoof') {
119 | // Set new user-agent string based on the saved fingerprint for the referring domain
120 | httpChannel.setRequestHeader("User-Agent", webID.fingerprint.useragent, false);
121 | // Set the Accept-Encoding header
122 | httpChannel.setRequestHeader("Accept-Encoding", webID.fingerprint.accept.acceptEncoding, false);
123 | } else
124 | if (detection.getAttribute(referrerDomain, 'User-Agent').action == 'block') {
125 | // Remove user-agent string for the referring domain
126 | httpChannel.setRequestHeader("User-Agent", "", false);
127 | // Remove the Accept-Encoding header
128 | httpChannel.setRequestHeader("Accept-Encoding", "", false);
129 | }
130 |
131 | if (!detection.getAttribute(referrerDomain, 'Language') || detection.getAttribute(referrerDomain, 'Language').action == 'spoof') {
132 | // Set the Accept-Language header
133 | httpChannel.setRequestHeader("Accept-Language", webID.fingerprint.navigator.language, false);
134 | } else
135 | if (detection.getAttribute(referrerDomain, 'Language').action == 'block') {
136 | // Remove the Accept-Language header
137 | httpChannel.setRequestHeader("Accept-Language", "", false);
138 | }
139 |
140 | // Remove possible ETag headers from request
141 | // NOTE: Setting a header to nothing and merge to false, removes the header from the request
142 | if (preferences.getBoolPref('deleteetags')) {
143 | httpChannel.setRequestHeader("If-Match", "", false);
144 | httpChannel.setRequestHeader("If-None-Match", "", false);
145 | httpChannel.setRequestHeader("If-Range", "", false);
146 | }
147 |
148 | if (referrerDomain.substring(0, referrerDomain.lastIndexOf(".")) != requestDomain.substring(0, requestDomain.lastIndexOf("."))) {
149 | // Get third-parties for the referring domain
150 | var thirdparties = webID.thirdparties;
151 | // Add requested domain to third-parties if not present
152 | var exists = false;
153 | var i = 0;
154 | while (!exists && i < thirdparties.length) {
155 | if (thirdparties[i].name == requestDomain) {
156 | exists = true;
157 | }
158 | i++;
159 | }
160 | if (!exists) {
161 | thirdparties.push({name : requestDomain, enabled : true});
162 | }
163 | // Block third-parties
164 | for (var i = 0; i < thirdparties.length; i++) {
165 | if (thirdparties[i].enabled == false) {
166 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
167 | }
168 | }
169 |
170 | // Remove referrer header from the request in order to preserve privacy
171 | // NOTE: Setting a header to nothing and merge to false, removes the header from the request
172 | //if (preferences.getBoolPref('deletereferer')) {
173 | // httpChannel.setRequestHeader("Referer", "", false);
174 | //}
175 |
176 | // SOCIAL PLUGINS:
177 | // We abort the communication and reject the request if it's part of a social plugin
178 |
179 | // Facebook
180 | if (httpChannel.originalURI.spec.indexOf("connect.facebook.net/en_US/all.js") != -1 ||
181 | httpChannel.originalURI.spec.indexOf("facebook.com/plugins/") != -1) {
182 | if (webID.socialplugins.facebook == undefined) {
183 | if (preferences.getBoolPref('autoblocksocial')) {
184 | webID.socialplugins.facebook = false;
185 | } else {
186 | webID.socialplugins.facebook = true;
187 | }
188 | }
189 | if (!webID.socialplugins.facebook) {
190 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
191 | }
192 | }
193 | // Twitter
194 | if (httpChannel.originalURI.spec.indexOf("platform.twitter.com/widgets.js") != -1 ||
195 | httpChannel.originalURI.spec.indexOf("platform.twitter.com/widgets/") != -1) {
196 | if (webID.socialplugins.twitter == undefined) {
197 | if (preferences.getBoolPref('autoblocksocial')) {
198 | webID.socialplugins.twitter = false;
199 | } else {
200 | webID.socialplugins.twitter = true;
201 | }
202 | }
203 | if (!webID.socialplugins.twitter) {
204 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
205 | }
206 | }
207 | // Google Plus
208 | if (httpChannel.originalURI.spec.indexOf("apis.google.com/js/platform.js") != -1 ||
209 | httpChannel.originalURI.spec.indexOf("apis.google.com/js/plusone.js") != -1) {
210 | if (webID.socialplugins.googleplus == undefined) {
211 | if (preferences.getBoolPref('autoblocksocial')) {
212 | webID.socialplugins.googleplus = false;
213 | } else {
214 | webID.socialplugins.googleplus = true;
215 | }
216 | }
217 | if (!webID.socialplugins.googleplus) {
218 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
219 | }
220 | }
221 | // LinkedIn
222 | if (httpChannel.originalURI.spec.indexOf("platform.linkedin.com/in.js") != -1) {
223 | if (webID.socialplugins.linkedin == undefined) {
224 | if (preferences.getBoolPref('autoblocksocial')) {
225 | webID.socialplugins.linkedin = false;
226 | } else {
227 | webID.socialplugins.linkedin = true;
228 | }
229 | }
230 | if (!webID.socialplugins.linkedin) {
231 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
232 | }
233 | }
234 | // Tumblr
235 | if (httpChannel.originalURI.spec.indexOf("platform.tumblr.com/v1/") != -1) {
236 | if (webID.socialplugins.tumblr == undefined) {
237 | if (preferences.getBoolPref('autoblocksocial')) {
238 | webID.socialplugins.tumblr = false;
239 | } else {
240 | webID.socialplugins.tumblr = true;
241 | }
242 | }
243 | if (!webID.socialplugins.tumblr) {
244 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
245 | }
246 | }
247 | // Pinterest
248 | if (httpChannel.originalURI.spec.indexOf("assets.pinterest.com/js/pinit.js") != -1) {
249 | if (webID.socialplugins.pinterest == undefined) {
250 | if (preferences.getBoolPref('autoblocksocial')) {
251 | webID.socialplugins.pinterest = false;
252 | } else {
253 | webID.socialplugins.pinterest = true;
254 | }
255 | }
256 | if (!webID.socialplugins.pinterest) {
257 | httpChannel.cancel(Components.results.NS_BINDING_ABORTED);
258 | }
259 | }
260 | }
261 | }
262 | } catch(e) {
263 | Components.utils.reportError(e);
264 | }
265 | } else
266 | // On HTTP response
267 | if (topic == "http-on-examine-response" || topic == "http-on-examine-cached-response") {
268 | if (subject instanceof Ci.nsIHttpChannel) {
269 | subject.QueryInterface(Ci.nsITraceableChannel);
270 | subject.QueryInterface(Ci.nsIHttpChannel);
271 | var newListener = new responseListener();
272 | newListener.originalListener = subject.setNewListener(newListener);
273 | }
274 | }
275 | },
276 |
277 | QueryInterface : function(aIID) {
278 | if (aIID.equals(Ci.nsIObserver) || aIID.equals(Ci.nsISupports)) {
279 | return this;
280 | }
281 | throw Components.results.NS_NOINTERFACE;
282 | },
283 |
284 | register : function() {
285 | this.observerService.addObserver(this, "http-on-modify-request", false);
286 | this.observerService.addObserver(this, "http-on-examine-response", false);
287 | this.observerService.addObserver(this, "http-on-examine-cached-response", false);
288 | },
289 |
290 | unregister : function() {
291 | this.observerService.removeObserver(this, "http-on-modify-request");
292 | this.observerService.removeObserver(this, "http-on-examine-response");
293 | this.observerService.removeObserver(this, "http-on-examine-cached-response");
294 | },
295 |
296 | get observerService() {
297 | return Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
298 | }
299 | };
300 |
--------------------------------------------------------------------------------
/Plugin/modules/preferencesObserver.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 26.08.2015 */
5 | /****************************************************************/
6 |
7 | var EXPORTED_SYMBOLS = ["preferencesDNTObserver"];
8 | var EXPORTED_SYMBOLS = ["preferencesThirdPartiesObserver"];
9 | var EXPORTED_SYMBOLS = ["preferencesAutomaticConnectionsObserver"];
10 |
11 | var Cc = Components.classes;
12 | var Ci = Components.interfaces;
13 |
14 | var preferencesThirdPartiesObserver = {
15 | observe: function(aSubject, aTopic, aData) {
16 | // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
17 | // aData is the name of the pref that's been changed (relative to aSubject)
18 | switch (aData) {
19 | // network.cookie.cookieBehavior was changed
20 | case "cookieBehavior":
21 | var fpblockpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
22 | var firefoxpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('network.cookie.');
23 | if (firefoxpreferences.getIntPref('cookieBehavior') == 1) {
24 | fpblockpreferences.setBoolPref('blockthirdparties', true);
25 | } else {
26 | fpblockpreferences.setBoolPref('blockthirdparties', false);
27 | }
28 | break;
29 | }
30 | },
31 |
32 | register: function() {
33 | // First we'll need the preference services to look for preferences.
34 | var prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
35 |
36 | // For this.branch we ask for the preferences for network.cookie. and children
37 | this.branch = prefService.getBranch("network.cookie.");
38 |
39 | // Now we queue the interface called nsIPrefBranch2. This interface is described as:
40 | // "nsIPrefBranch2 allows clients to observe changes to pref values."
41 | // This is only necessary prior to Gecko 13
42 | if (!("addObserver" in this.branch))
43 | this.branch.QueryInterface(Ci.nsIPrefBranch2);
44 |
45 | // Finally add the observer.
46 | this.branch.addObserver("", this, false);
47 | },
48 |
49 | unregister: function() {
50 | this.branch.removeObserver("", this);
51 | }
52 | };
53 |
54 | var preferencesDNTObserver = {
55 | observe: function(aSubject, aTopic, aData) {
56 | // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
57 | // aData is the name of the pref that's been changed (relative to aSubject)
58 | switch (aData) {
59 | // privacy.donottrackheader.enabled was changed
60 | case "enabled":
61 | var fpblockpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
62 | fpblockpreferences.setBoolPref('dntheader', !fpblockpreferences.getBoolPref('dntheader'));
63 | break;
64 | }
65 | },
66 |
67 | register: function() {
68 | // First we'll need the preference services to look for preferences.
69 | var prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
70 |
71 | // For this.branch we ask for the preferences for privacy.donottrackheader. and children
72 | this.branch = prefService.getBranch("privacy.donottrackheader.");
73 |
74 | // Now we queue the interface called nsIPrefBranch2. This interface is described as:
75 | // "nsIPrefBranch2 allows clients to observe changes to pref values."
76 | // This is only necessary prior to Gecko 13
77 | if (!("addObserver" in this.branch))
78 | this.branch.QueryInterface(Ci.nsIPrefBranch2);
79 |
80 | // Finally add the observer.
81 | this.branch.addObserver("", this, false);
82 | },
83 |
84 | unregister: function() {
85 | this.branch.removeObserver("", this);
86 | }
87 | };
88 |
89 | var preferencesAutomaticConnectionsObserver = {
90 | observe: function(aSubject, aTopic, aData) {
91 | // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
92 | // aData is the name of the pref that's been changed (relative to aSubject)
93 | switch (aData) {
94 | // network.http.speculative-parallel-limit was changed
95 | case "http.speculative-parallel-limit":
96 | var fpblockpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
97 | var firefoxpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('network.http.');
98 | if (firefoxpreferences.getIntPref('speculative-parallel-limit') == 0) {
99 | fpblockpreferences.setBoolPref('autoblockconnections', true);
100 | } else {
101 | fpblockpreferences.setBoolPref('autoblockconnections', false);
102 | }
103 | break;
104 | // network.dns.disablePrefetch was changed
105 | case "dns.disablePrefetch":
106 | var fpblockpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
107 | fpblockpreferences.setBoolPref('autoblockconnections', !fpblockpreferences.getBoolPref('autoblockconnections'));
108 | break;
109 | // network.prefetch-next was changed
110 | case "prefetch-next":
111 | var fpblockpreferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
112 | fpblockpreferences.setBoolPref('autoblockconnections', !fpblockpreferences.getBoolPref('autoblockconnections'));
113 | break;
114 | }
115 | },
116 |
117 | register: function() {
118 | // First we'll need the preference services to look for preferences.
119 | var prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
120 |
121 | // For this.branch we ask for the preferences for network. and children
122 | this.branch = prefService.getBranch("network.");
123 |
124 | // Now we queue the interface called nsIPrefBranch2. This interface is described as:
125 | // "nsIPrefBranch2 allows clients to observe changes to pref values."
126 | // This is only necessary prior to Gecko 13
127 | if (!("addObserver" in this.branch))
128 | this.branch.QueryInterface(Ci.nsIPrefBranch2);
129 |
130 | // Finally add the observer.
131 | this.branch.addObserver("", this, false);
132 | },
133 |
134 | unregister: function() {
135 | this.branch.removeObserver("", this);
136 | }
137 | };
138 |
--------------------------------------------------------------------------------
/Plugin/modules/profiles.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 14.12.2014 */
5 | /****************************************************************/
6 |
7 | Components.utils.import("resource://gre/modules/AddonManager.jsm");
8 | Components.utils.import("resource://gre/modules/FileUtils.jsm");
9 | Components.utils.import("resource://gre/modules/NetUtil.jsm");
10 |
11 | var EXPORTED_SYMBOLS = ["profiles"];
12 |
13 | var profiles = [];
14 |
15 | AddonManager.getAddonByID("fpblock@fingerprint.christoftorres.com", function(addon) {
16 | var uri = addon.getResourceURI("/profiles");
17 | if (uri instanceof Components.interfaces.nsIFileURL) {
18 | var entries = uri.file.directoryEntries;
19 | while(entries.hasMoreElements()) {
20 | var entry = entries.getNext();
21 | entry.QueryInterface(Components.interfaces.nsIFile);
22 | var channel = NetUtil.newChannel(entry);
23 | channel.contentType = "application/json";
24 | NetUtil.asyncFetch(channel, function(inputStream, status) {
25 | if (!Components.isSuccessCode(status)) {
26 | // Handle error!
27 | Components.utils.reportError("Error fetching profile!");
28 | return;
29 | }
30 | // The file data is contained within inputStream.
31 | // You can read it into a string with
32 | var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
33 | // Parse the JSON file into an object and add it to the profiles
34 | profiles.push(JSON.parse(data));
35 | });
36 | }
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/Plugin/modules/randomFingerprintGenerator.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 11.02.2015 */
5 | /****************************************************************/
6 |
7 | var EXPORTED_SYMBOLS = ["randomFingerprintGenerator"];
8 |
9 | Components.utils.import("resource://lib/profiles.jsm");
10 |
11 | var Cc = Components.classes;
12 | var Ci = Components.interfaces;
13 |
14 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
15 |
16 | /*
17 | This random fingerprint generator is based on Jeffrey Mealo random user-agent
18 | generator version 0.0.6 which is under the MIT license.
19 | Author: Jeffrey Mealo
20 | E-mail: jeffreymealo@gmail.com
21 | Web : http://www.jeffreymealo.com
22 | URL : https://github.com/jmealo/random-ua.js.git
23 | */
24 |
25 | /*
26 | This generator was updated to generate random fingerprints based on a particular random profile.
27 | Author: Christof Ferreira Torres
28 | E-mail: christof.ferreira.001@student.uni.lu
29 | */
30 |
31 | function random(a, b) {
32 | //calling random() with no arguments is identical to random(0, 100)
33 | a = a || 0;
34 | b = b || 100;
35 |
36 | if (typeof b === 'number' && typeof a === 'number') {
37 | //random(int min, int max) returns an integer between min, max
38 | return (function (min, max) {
39 | if (min > max) {
40 | throw new RangeError('expected min <= max; got min = ' + min + ', max = ' + max);
41 | }
42 | return Math.floor(Math.random() * (max - min + 1)) + min;
43 | }(a, b));
44 | }
45 |
46 | if (Object.prototype.toString.call(a) === "[object Array]") {
47 | //returns a random element from array (a), even weighting
48 | return a[Math.floor(Math.random() * a.length)];
49 | }
50 |
51 | if (a && typeof a === 'object') {
52 | //returns a random key from the passed object; keys are weighted by the decimal probability in their value
53 | return (function (obj) {
54 | var rand = random(0, 100) / 100, min = 0, max = 0, key, return_val;
55 |
56 | for (key in obj) {
57 | if (obj.hasOwnProperty(key)) {
58 | max = obj[key] + min;
59 | return_val = key;
60 | if (rand >= min && rand <= max) {
61 | break;
62 | }
63 | min = min + obj[key];
64 | }
65 | }
66 |
67 | return return_val;
68 | }(a));
69 | }
70 |
71 | throw new TypeError('Invalid arguments passed to random. (' + (b ? a + ', ' + b : a) + ')');
72 | }
73 |
74 | /**
75 | * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)
76 | *
77 | * @author Gary Court
78 | * @see http://github.com/garycourt/murmurhash-js
79 | * @author Austin Appleby
80 | * @see http://sites.google.com/site/murmurhash/
81 | *
82 | * @param {string} key ASCII only
83 | * @param {number} seed Positive integer only
84 | * @return {number} 32-bit positive integer hash
85 | */
86 | function murmurhash3_32_gc(key, seed) {
87 | var remainder, bytes, h1, h1b, c1, c2, k1, i;
88 |
89 | remainder = key.length & 3; // key.length % 4
90 | bytes = key.length - remainder;
91 | h1 = seed;
92 | c1 = 0xcc9e2d51;
93 | c2 = 0x1b873593;
94 | i = 0;
95 |
96 | while (i < bytes) {
97 | k1 =
98 | ((key.charCodeAt(i) & 0xff)) |
99 | ((key.charCodeAt(++i) & 0xff) << 8) |
100 | ((key.charCodeAt(++i) & 0xff) << 16) |
101 | ((key.charCodeAt(++i) & 0xff) << 24);
102 | ++i;
103 |
104 | k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
105 | k1 = (k1 << 15) | (k1 >>> 17);
106 | k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
107 |
108 | h1 ^= k1;
109 | h1 = (h1 << 13) | (h1 >>> 19);
110 | h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
111 | h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
112 | }
113 |
114 | k1 = 0;
115 |
116 | switch (remainder) {
117 | case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
118 | case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
119 | case 1: k1 ^= (key.charCodeAt(i) & 0xff);
120 |
121 | k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
122 | k1 = (k1 << 15) | (k1 >>> 17);
123 | k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
124 | h1 ^= k1;
125 | }
126 |
127 | h1 ^= key.length;
128 |
129 | h1 ^= h1 >>> 16;
130 | h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
131 | h1 ^= h1 >>> 13;
132 | h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
133 | h1 ^= h1 >>> 16;
134 |
135 | return h1 >>> 0;
136 | }
137 |
138 | var version_string = {
139 | nt: function (profile) {
140 | return random(profile.versions.nt.major.min, profile.versions.nt.major.max) + '.' + random(profile.versions.nt.minor.min, profile.versions.nt.minor.max);
141 | },
142 | osx: function (profile, delim) {
143 | return [10, random(profile.versions.osx.major.min, profile.versions.osx.major.max), random(profile.versions.osx.minor.min, profile.versions.osx.minor.max)].join(delim || '.');
144 | }
145 | };
146 |
147 | var useragent = {
148 | firefox: function firefox(profile, os, proc, language) {
149 | //https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
150 | var firefox_ver = random(profile.versions.major.min, profile.versions.major.max) + getRandomRevision(2, profile.versions.revision),
151 | gecko_ver = profile.versions.gecko + firefox_ver,
152 | os_ver = (os === 'win') ? '(Windows NT ' + version_string.nt(profile) + ((proc) ? '; ' + proc : '')
153 | : (os === 'mac') ? '(Macintosh; ' + proc + ' Mac OS X ' + version_string.osx(profile)
154 | : '(X11; Linux ' + proc;
155 |
156 | return 'Mozilla/5.0 ' + os_ver + '; rv:' + firefox_ver.slice(0, -2) + ') ' + gecko_ver;
157 | },
158 |
159 | opera: function opera(profile, os, proc, language) {
160 | //http://www.opera.com/docs/history/
161 | var presto = profile.versions.presto.major + random(profile.versions.presto.minor.min, profile.versions.presto.minor.max),
162 | presto2 = random(profile.versions.presto2.major.min, profile.versions.presto2.major.max) + profile.versions.presto2.minor,
163 | presto_ver = ' Presto/' + presto + ' Version/' + presto2 + ')',
164 | os_ver = (os === 'win') ? '(Windows NT ' + version_string.nt(profile) + '; U; ' + language + presto_ver
165 | : (os === 'lin') ? '(X11; Linux ' + proc + '; U; ' + language + presto_ver
166 | : '(Macintosh; Intel Mac OS X ' + version_string.osx(profile, '_') + ' U; ' + language + ' Presto/' + presto + ' Version/' + presto2 + ')';
167 |
168 | return 'Opera/' + random(profile.versions.major.min, profile.versions.major.max) + '.' + random(profile.versions.minor.min, profile.versions.minor.max) + ' ' + os_ver;
169 | },
170 |
171 | safari: function safari(profile, os, proc, language) {
172 | var safari = random(profile.versions.applewebkit.major.min, profile.versions.applewebkit.major.max) + '.' + random(profile.versions.applewebkit.minor.min, profile.versions.applewebkit.minor.max) + '.' + random(profile.versions.applewebkit.build.min, profile.versions.applewebkit.build.max),
173 | ver = (random(0, 1) === 0) ? '0.' + random(profile.versions.build.min, profile.versions.build.max) : random(profile.versions.minor.min, profile.versions.minor.max),
174 | os_ver = (os === 'mac') ? '(Macintosh; ' + proc + ' Mac OS X '+ version_string.osx(profile, '_') + ' rv:' + random(2, 6) + '.0; '+ language + ') '
175 | : '(Windows; U; Windows NT ' + version_string.nt(profile) + ')';
176 |
177 | return 'Mozilla/5.0 ' + os_ver + ' AppleWebKit/' + safari + ' (KHTML, like Gecko) Version/' + random(profile.versions.major.min, profile.versions.major.max) + '.' + ver + ' Safari/' + safari;
178 | },
179 |
180 | chrome: function chrome(profile, os, proc, language) {
181 | var safari = random(profile.versions.applewebkit.major.min, profile.versions.applewebkit.major.max) + '.' + random(profile.versions.applewebkit.minor.min, profile.versions.applewebkit.minor.max) + '.' + random(profile.versions.applewebkit.build.min, profile.versions.applewebkit.build.max),
182 | os_ver = (os === 'mac') ? '(Macintosh; ' + proc + ' Mac OS X ' + version_string.osx(profile, '_') + ') '
183 | : (os === 'win') ? '(Windows; U; Windows NT ' + version_string.nt(profile) + ')'
184 | : '(X11; Linux ' + proc;
185 |
186 | return 'Mozilla/5.0 ' + os_ver + ' AppleWebKit/' + safari + ' (KHTML, like Gecko) Chrome/' + [random(profile.versions.major.min, profile.versions.major.max), 0, random(profile.versions.build.min, profile.versions.build.max), 0].join('.') + ' Safari/' + safari;
187 | }
188 | };
189 |
190 | function getRandomProfile() {
191 | return random(profiles);
192 | }
193 |
194 | function getRandomOS(profile) {
195 | return random(profile.os);
196 | }
197 |
198 | function getRandomProcessor(profile, os) {
199 | return random(profile.procs[os]);
200 | }
201 |
202 | function getRandomRevision(dots, revision) {
203 | var return_val = '';
204 | for (var x = 0; x < dots; x++) {
205 | return_val += '.' + random(0, revision);
206 | }
207 | return return_val;
208 | }
209 |
210 | function getRandomUserAgent(profile, os, proc, language) {
211 | return useragent[profile.browser](profile, os, proc, language);
212 | }
213 |
214 | function getRandomLanguage(profile) {
215 | return random(profile.languages);
216 | }
217 |
218 | function getRandomNavigatorObject(profile, os, proc, language, useragent) {
219 | var platform = (os === 'win') ? 'Win32' : (os === 'mac') ? 'MacIntel' : 'Linux ' + proc;
220 | var cpuClass = (proc.contains('Intel')) ? 'x86' : (proc.contains('86')) ? 'x86' : (proc.contains('PPC')) ? 'PPC' : 'Other';
221 | var appVersion = (profile.browser === 'opera') ? useragent : useragent.substring(8, useragent.length);
222 | return {
223 | appCodeName : profile.appCodeName,
224 | appName : profile.appName,
225 | language : language,
226 | appVersion : appVersion,
227 | platform : platform,
228 | oscpu : platform,
229 | product : profile.product,
230 | vendor : profile.vendor,
231 | cpuClass : cpuClass,
232 | systemLanguage : language,
233 | userLanguage : language
234 | };
235 | }
236 |
237 | function getRandomScreenObject(profile) {
238 | var screenresolution = random(profile.screen.resolutions);
239 | var colordepth = random(profile.screen.colordepth);
240 | return {
241 | width : parseInt(screenresolution.split('x')[0]),
242 | height : parseInt(screenresolution.split('x')[1]),
243 | colorDepth : parseInt(colordepth),
244 | availWidth : parseInt(screenresolution.split('x')[0]),
245 | availHeight : parseInt(screenresolution.split('x')[1])-profile.screen.toolbar,
246 | pixelDepth : parseInt(colordepth)
247 | };
248 | }
249 |
250 | function getRandomDateObject(profile) {
251 | return {
252 | timezoneOffset : random(profile.timezones)
253 | };
254 | }
255 |
256 | function getAcceptObject(profile) {
257 | return {
258 | acceptEncoding : profile.http.encoding
259 | };
260 | }
261 |
262 | function checkUniqueness(generatedFingerprint, webIdentities) {
263 | if (webIdentities.length > 0) {
264 | var i = 0;
265 | var unique = true;
266 | while (unique && i < webIdentities.length) {
267 | if (generatedFingerprint.hash == webIdentities[i].hash) {
268 | unique = false;
269 | }
270 | i++;
271 | }
272 | return unique;
273 | } else {
274 | return true;
275 | }
276 | }
277 |
278 | var randomFingerprintGenerator = {
279 | generate : function() {
280 | var profile = getRandomProfile();
281 | var os = getRandomOS(profile);
282 | var proc = getRandomProcessor(profile, os);
283 | var language = getRandomLanguage(profile);
284 | var useragent = getRandomUserAgent(profile, os, proc, language);
285 | var navigatorObject = getRandomNavigatorObject(profile, os, proc, language, useragent);
286 | var screenObject = getRandomScreenObject(profile);
287 | var dateObject = getRandomDateObject(profile);
288 | var acceptObject = getAcceptObject(profile);
289 | var fingerprint = {useragent : useragent, navigator : navigatorObject, screen : screenObject, date : dateObject, accept : acceptObject};
290 | var hash = this.generateHash(fingerprint);
291 | var currentTime = new Date().getTime();
292 | return {profile : profile, fingerprint : fingerprint, hash : hash, usage : {amount : 1, date : currentTime}};
293 | },
294 |
295 | generateAndCheckUniqueness : function(webIdentities) {
296 | // As long as we didn't reach the limit of unique web identities...
297 | if (webIdentities.length < preferences.getIntPref('webidentitieslimit')) {
298 | // ...and as long as the fingerprint is not unique, generate a new fingerprint
299 | // and check its uniqueness among the existing web identities
300 | var generatedFingerprint;
301 | do {
302 | generatedFingerprint = this.generate();
303 | } while (!checkUniqueness(generatedFingerprint, webIdentities));
304 | // Return the unique generated fingerprint
305 | return generatedFingerprint;
306 | } else {
307 | // Ok we reached the limit! Now we have to pick the least-used web identity and reuse it
308 | var leastused = webIdentities[0];
309 | for (var i = 1; i < webIdentities.length; i++) {
310 | if (webIdentities[i].usage.amount < leastused.usage.amount) {
311 | leastused = webIdentities[i];
312 | } else
313 | if (webIdentities[i].usage.amount = leastused.usage.amount) {
314 | if (webIdentities[i].usage.date < leastused.usage.date) {
315 | leastused = webIdentities[i];
316 | }
317 | }
318 | }
319 | leastused.usage.amount++;
320 | // Return the least-used profile, fingerprint, hash, usage and domain
321 | var currentTime = new Date().getTime();
322 | return {profile : leastused.profile, fingerprint : leastused.fingerprint, hash : leastused.hash, usage : {amount : leastused.usage.amount, date : currentTime}};
323 | }
324 | },
325 |
326 | generateHash : function(fingerprint) {
327 | // Group 0 - Browser
328 | /*var group0 = fingerprint.useragent + '###' +
329 | fingerprint.navigator.appCodeName + '###' +
330 | fingerprint.navigator.appName + '###' +
331 | fingerprint.navigator.appVersion + '###' +
332 | fingerprint.navigator.product + '###' +
333 | fingerprint.navigator.vendor + '###' +
334 | fingerprint.accept.acceptEncoding;*/
335 | // Group 1 - OS & CPU
336 | var group1 = fingerprint.navigator.platform + '###' +
337 | fingerprint.navigator.oscpu + '###' +
338 | fingerprint.navigator.cpuClass;
339 | // Group 2 - Screen Resolution
340 | var group2 = fingerprint.screen.width + '###' +
341 | fingerprint.screen.height + '###' +
342 | fingerprint.screen.colorDepth + '###' +
343 | fingerprint.screen.availWidth + '###' +
344 | fingerprint.screen.availHeight + '###' +
345 | fingerprint.screen.pixelDepth;
346 | // Group 3 - Timezone
347 | var group3 = fingerprint.date.timezoneOffset;
348 | // Group 4 - Language
349 | var group4 = fingerprint.navigator.language + '###' +
350 | fingerprint.navigator.systemLanguage + '###' +
351 | fingerprint.navigator.userLanguage;
352 | // Return the two hashes for Group 0 and Group 1 until Group 4
353 | return murmurhash3_32_gc(group1 + '###' + group2 + '###' + group3 + '###' + group4, 31);
354 | },
355 |
356 | generateAppCodeName : function(profile) {
357 | return profile.appcodename;
358 | },
359 |
360 | generateAppName : function(profile) {
361 | return profile.appname;
362 | },
363 |
364 | generateUserAgentAndNavigatorObject : function(profile) {
365 | var os = getRandomOS(profile);
366 | var proc = getRandomProcessor(profile, os);
367 | var language = getRandomLanguage(profile);
368 | var useragent = getRandomUserAgent(profile, os, proc, language);
369 | var navigatorObject = getRandomNavigatorObject(profile, os, proc, language, useragent);
370 | return {useragent : useragent, navigatorObject : navigatorObject};
371 | },
372 |
373 | generateLanguage : function(profile) {
374 | return getRandomLanguage(profile);
375 | },
376 |
377 | generateProduct : function(profile) {
378 | return profile.product;
379 | },
380 |
381 | generateVendor : function(profile) {
382 | return profile.vendor;
383 | },
384 |
385 | generateScreenObject : function(profile) {
386 | return getRandomScreenObject(profile);
387 | },
388 |
389 | generateTimezone : function(profile) {
390 | return getRandomDateObject(profile);
391 | }
392 | };
393 |
--------------------------------------------------------------------------------
/Plugin/modules/webIdentity.jsm:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- FP-Block -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 11.02.2015 */
5 | /****************************************************************/
6 |
7 | var EXPORTED_SYMBOLS = ["webIdentity", "privateWebIdentity"];
8 |
9 | var Cc = Components.classes;
10 | var Ci = Components.interfaces;
11 |
12 | var webIdentity = {
13 | webidentities : [],
14 |
15 | loadWebIdentities : function() {
16 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
17 | this.webidentities = JSON.parse(preferences.getCharPref('webidentities'));
18 | },
19 |
20 | saveWebIdentities : function() {
21 | var preferences = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService).getBranch('extensions.fpblock.');
22 | preferences.setCharPref('webidentities', JSON.stringify(this.webidentities));
23 | },
24 |
25 | clearWebIdentities : function() {
26 | this.webidentities = [];
27 | },
28 |
29 | deleteWebIdentity : function(domain) {
30 | for (var i = 0; i < this.webidentities.length; i++) {
31 | if (this.webidentities[i].domain == domain) {
32 | this.webidentities.splice(i,1);
33 | return;
34 | }
35 | }
36 | },
37 |
38 | addWebIdentity : function(domain, fingerprint, profile, hash, usage, socialplugins, browserplugins) {
39 | this.webidentities.push({domain : domain, fingerprint : fingerprint, profile : profile, hash : hash, usage : usage, thirdparties : [], socialplugins : socialplugins, browserplugins : browserplugins, enabled : true});
40 | },
41 |
42 | getWebIdentity : function(domain) {
43 | for (var i = 0; i < this.webidentities.length; i++) {
44 | if (this.webidentities[i].domain == domain) {
45 | return this.webidentities[i];
46 | }
47 | }
48 | return null;
49 | },
50 |
51 | getWebIdentities : function() {
52 | return this.webidentities;
53 | }
54 | };
55 |
56 | var privateWebIdentity = {
57 | privatewebidentities : [],
58 |
59 | clearPrivateWebIdentities : function() {
60 | this.privatewebidentities = [];
61 | },
62 |
63 | addPrivateWebIdentity : function(domain, fingerprint, profile, hash, usage, socialplugins, browserplugins) {
64 | this.privatewebidentities.push({domain : domain, fingerprint : fingerprint, profile : profile, hash : hash, usage : usage, thirdparties : [], socialplugins : socialplugins, browserplugins : browserplugins, enabled : true});
65 | },
66 |
67 | getPrivateWebIdentity : function(domain) {
68 | for (var i = 0; i < this.privatewebidentities.length; i++) {
69 | if (this.privatewebidentities[i].domain == domain) {
70 | return this.privatewebidentities[i];
71 | }
72 | }
73 | return null;
74 | },
75 |
76 | getPrivateWebIdentities : function() {
77 | return this.privatewebidentities;
78 | }
79 | };
80 |
--------------------------------------------------------------------------------
/Plugin/profiles/chrome.json:
--------------------------------------------------------------------------------
1 | {
2 | "browser" : "chrome",
3 | "os" : {
4 | "win" : 0.89,
5 | "mac" : 0.09,
6 | "lin" : 0.02
7 | },
8 | "procs" : {
9 | "win" : ["", "WOW64", "Win64; x64"],
10 | "mac" : {"Intel" : 0.48, "PPC" : 0.01, "U; Intel" : 0.48, "U; PPC" : 0.01},
11 | "lin" : ["i686", "x86_64"]
12 | },
13 | "versions" : {
14 | "major" : {"min" : 13, "max" : 39},
15 | "build" : {"min" : 800, "max" : 899},
16 | "applewebkit" : {
17 | "major" : {"min" : 531, "max" : 538},
18 | "minor" : {"min" : 0, "max" : 2},
19 | "build" : {"min" : 0, "max" : 2}
20 | },
21 | "nt" : {
22 | "major" : {"min" : 5, "max" : 6},
23 | "minor" : {"min" : 0, "max" : 3}
24 | },
25 | "osx" : {
26 | "major" : {"min" : 5, "max" : 10},
27 | "minor" : {"min" : 0, "max" : 9}
28 | }
29 | },
30 | "screen" : {
31 | "resolutions" : ["1366x768", "1024x768", "1280x800", "1920x1080", "1280x1024", "1440x900", "1600x900", "1680x1050", "1360x768"],
32 | "colordepth" : [16, 24, 32],
33 | "toolbar" : 42
34 | },
35 | "languages" : ["af", "sq", "ar-SA", "ar-IQ", "ar-EG", "ar-LY", "ar-DZ", "ar-MA", "ar-TN", "ar-OM", "ar-YE", "ar-SY", "ar-JO", "ar-LB", "ar-KW",
36 | "ar-AE", "ar-BH", "ar-QA", "eu", "bg", "be", "ca", "zh-TW", "zh-CN", "zh-HK", "zh-SG", "hr", "cs", "da", "nl", "nl-BE", "en", "en-US",
37 | "en-GB", "en-AU", "en-CA", "en-NZ", "en-IE", "en-ZA", "en-JM", "en-BZ", "en-TT", "et", "fo", "fa", "fi", "fr", "fr-BE", "fr-CA",
38 | "fr-CH", "fr-LU", "gd", "gd-IE", "de", "de-CH", "de-AT", "de-LU", "de-LI", "el", "he", "hi", "hu", "is", "id", "it", "it-CH", "ja",
39 | "ko", "lv", "lt", "mk", "ms", "mt", "no", "pl", "pt-BR", "pt-PT", "rm", "ro", "ro-MO", "ru", "ru-MO", "sz", "sr", "sk", "sl", "sb",
40 | "es", "es-AR", "es-GT", "es-CR", "es-PA", "es-DO", "es-MX", "es-VE", "es-CO", "es-PE", "es-EC", "es-CL", "es-UY", "es-PY", "es-BO",
41 | "es-SV", "es-HN", "es-NI", "es-PR", "sx", "sv", "sv-FI", "th", "ts", "tn", "tr", "uk", "ur", "ve", "vi", "xh", "ji", "zu"],
42 | "http" : {
43 | "order" : ["Host", "Accept", "User-Agent", "Accept-Encoding", "Accept-Language"],
44 | "encoding" : "gzip,deflate,sdch"
45 | },
46 | "timezones" : [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270,
47 | -240, -210, -180, -120, -60, 0, 60, 120, 180, 210,
48 | 240, 270, 300, 330, 345, 360, 390, 420, 480, 525,
49 | 540, 570, 600, 630, 660, 690, 720, 765, 780, 840],
50 | "appcodename" : "Mozilla",
51 | "appname" : "Netscape",
52 | "product" : "Gecko",
53 | "vendor" : "Google Inc."
54 | }
--------------------------------------------------------------------------------
/Plugin/profiles/firefox.json:
--------------------------------------------------------------------------------
1 | {
2 | "browser" : "firefox",
3 | "os" : {
4 | "win" : 0.83,
5 | "mac" : 0.16,
6 | "lin" : 0.01
7 | },
8 | "procs" : {
9 | "win" : ["", "WOW64", "Win64; x64"],
10 | "mac" : {"Intel" : 0.48, "PPC" : 0.01, "U; Intel" : 0.48, "U; PPC" : 0.01},
11 | "lin" : ["i686", "x86_64"]
12 | },
13 | "versions" : {
14 | "major" : {"min" : 5, "max" : 33},
15 | "revision" : 9,
16 | "gecko" : "Gecko/20100101 Firefox/",
17 | "nt" : {
18 | "major" : {"min" : 5, "max" : 6},
19 | "minor" : {"min" : 0, "max" : 3}
20 | },
21 | "osx" : {
22 | "major" : {"min" : 5, "max" : 10},
23 | "minor" : {"min" : 0, "max" : 9}
24 | }
25 | },
26 | "screen" : {
27 | "resolutions" : ["1366x768", "1024x768", "1280x800", "1920x1080", "1280x1024", "1440x900", "1600x900", "1680x1050", "1360x768"],
28 | "colordepth" : [16, 24, 32],
29 | "toolbar" : 74
30 | },
31 | "languages" : ["af", "sq", "ar-SA", "ar-IQ", "ar-EG", "ar-LY", "ar-DZ", "ar-MA", "ar-TN", "ar-OM", "ar-YE", "ar-SY", "ar-JO", "ar-LB", "ar-KW",
32 | "ar-AE", "ar-BH", "ar-QA", "eu", "bg", "be", "ca", "zh-TW", "zh-CN", "zh-HK", "zh-SG", "hr", "cs", "da", "nl", "nl-BE", "en", "en-US",
33 | "en-GB", "en-AU", "en-CA", "en-NZ", "en-IE", "en-ZA", "en-JM", "en-BZ", "en-TT", "et", "fo", "fa", "fi", "fr", "fr-BE", "fr-CA",
34 | "fr-CH", "fr-LU", "gd", "gd-IE", "de", "de-CH", "de-AT", "de-LU", "de-LI", "el", "he", "hi", "hu", "is", "id", "it", "it-CH", "ja",
35 | "ko", "lv", "lt", "mk", "ms", "mt", "no", "pl", "pt-BR", "pt-PT", "rm", "ro", "ro-MO", "ru", "ru-MO", "sz", "sr", "sk", "sl", "sb",
36 | "es", "es-AR", "es-GT", "es-CR", "es-PA", "es-DO", "es-MX", "es-VE", "es-CO", "es-PE", "es-EC", "es-CL", "es-UY", "es-PY", "es-BO",
37 | "es-SV", "es-HN", "es-NI", "es-PR", "sx", "sv", "sv-FI", "th", "ts", "tn", "tr", "uk", "ur", "ve", "vi", "xh", "ji", "zu"],
38 | "http" : {
39 | "order" : ["Host", "User-Agent", "Accept", "Accept-Language", "Accept-Encoding"],
40 | "encoding" : "gzip, deflate"
41 | },
42 | "timezones" : [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270,
43 | -240, -210, -180, -120, -60, 0, 60, 120, 180, 210,
44 | 240, 270, 300, 330, 345, 360, 390, 420, 480, 525,
45 | 540, 570, 600, 630, 660, 690, 720, 765, 780, 840],
46 | "appcodename" : "Mozilla",
47 | "appname" : "Netscape",
48 | "product" : "Gecko",
49 | "vendor" : ""
50 | }
--------------------------------------------------------------------------------
/Plugin/profiles/opera.json:
--------------------------------------------------------------------------------
1 | {
2 | "browser" : "opera",
3 | "os" : {
4 | "win" : 0.91,
5 | "mac" : 0.03,
6 | "lin" : 0.06
7 | },
8 | "procs" : {
9 | "win" : ["", "WOW64", "Win64; x64"],
10 | "mac" : {"Intel" : 0.48, "PPC" : 0.01, "U; Intel" : 0.48, "U; PPC" : 0.01},
11 | "lin" : ["i686", "x86_64"]
12 | },
13 | "versions" : {
14 | "major" : {"min" : 9, "max" : 26},
15 | "minor" : {"min" : 0, "max" : 99},
16 | "presto" : {
17 | "major" : "2.9.",
18 | "minor" : {"min" : 160, "max" : 190}
19 | },
20 | "presto2" : {
21 | "major" : {"min" : 10, "max" : 14},
22 | "minor" : ".00"
23 | },
24 | "nt" : {
25 | "major" : {"min" : 5, "max" : 6},
26 | "minor" : {"min" : 0, "max" : 3}
27 | },
28 | "osx" : {
29 | "major" : {"min" : 5, "max" : 10},
30 | "minor" : {"min" : 0, "max" : 9}
31 | }
32 | },
33 | "screen" : {
34 | "resolutions" : ["1366x768", "1024x768", "1280x800", "1920x1080", "1280x1024", "1440x900", "1600x900", "1680x1050", "1360x768"],
35 | "colordepth" : [16, 24, 32],
36 | "toolbar" : 42
37 | },
38 | "languages" : ["af", "sq", "ar-SA", "ar-IQ", "ar-EG", "ar-LY", "ar-DZ", "ar-MA", "ar-TN", "ar-OM", "ar-YE", "ar-SY", "ar-JO", "ar-LB", "ar-KW",
39 | "ar-AE", "ar-BH", "ar-QA", "eu", "bg", "be", "ca", "zh-TW", "zh-CN", "zh-HK", "zh-SG", "hr", "cs", "da", "nl", "nl-BE", "en", "en-US",
40 | "en-GB", "en-AU", "en-CA", "en-NZ", "en-IE", "en-ZA", "en-JM", "en-BZ", "en-TT", "et", "fo", "fa", "fi", "fr", "fr-BE", "fr-CA",
41 | "fr-CH", "fr-LU", "gd", "gd-IE", "de", "de-CH", "de-AT", "de-LU", "de-LI", "el", "he", "hi", "hu", "is", "id", "it", "it-CH", "ja",
42 | "ko", "lv", "lt", "mk", "ms", "mt", "no", "pl", "pt-BR", "pt-PT", "rm", "ro", "ro-MO", "ru", "ru-MO", "sz", "sr", "sk", "sl", "sb",
43 | "es", "es-AR", "es-GT", "es-CR", "es-PA", "es-DO", "es-MX", "es-VE", "es-CO", "es-PE", "es-EC", "es-CL", "es-UY", "es-PY", "es-BO",
44 | "es-SV", "es-HN", "es-NI", "es-PR", "sx", "sv", "sv-FI", "th", "ts", "tn", "tr", "uk", "ur", "ve", "vi", "xh", "ji", "zu"],
45 | "http" : {
46 | "order" : ["Host", "Accept", "User-Agent", "Accept-Encoding", "Accept-Language"],
47 | "encoding" : "gzip,deflate,lzma,sdch"
48 | },
49 | "timezones" : [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270,
50 | -240, -210, -180, -120, -60, 0, 60, 120, 180, 210,
51 | 240, 270, 300, 330, 345, 360, 390, 420, 480, 525,
52 | 540, 570, 600, 630, 660, 690, 720, 765, 780, 840],
53 | "appcodename" : "Mozilla",
54 | "appname" : "Opera",
55 | "product" : "undefined",
56 | "vendor" : "undefined"
57 | }
--------------------------------------------------------------------------------
/Plugin/profiles/safari.json:
--------------------------------------------------------------------------------
1 | {
2 | "browser" : "safari",
3 | "os" : {
4 | "win" : 0.04,
5 | "mac" : 0.96
6 | },
7 | "procs" : {
8 | "win" : ["", "WOW64", "Win64; x64"],
9 | "mac" : {"Intel" : 0.48, "PPC" : 0.01, "U; Intel" : 0.48, "U; PPC" : 0.01}
10 | },
11 | "versions" : {
12 | "major" : {"min" : 4, "max" : 7},
13 | "minor" : {"min" : 0, "max" : 1},
14 | "build" : {"min" : 1, "max" : 5},
15 | "applewebkit" : {
16 | "major" : {"min" : 531, "max" : 538},
17 | "minor" : {"min" : 0, "max" : 2},
18 | "build" : {"min" : 0, "max" : 2}
19 | },
20 | "nt" : {
21 | "major" : {"min" : 5, "max" : 6},
22 | "minor" : {"min" : 0, "max" : 3}
23 | },
24 | "osx" : {
25 | "major" : {"min" : 5, "max" : 10},
26 | "minor" : {"min" : 0, "max" : 9}
27 | }
28 | },
29 | "screen" : {
30 | "resolutions" : ["1366x768", "1024x768", "1280x800", "1920x1080", "1280x1024", "1440x900", "1600x900", "1680x1050", "1360x768"],
31 | "colordepth" : [16, 24, 32],
32 | "toolbar" : 42
33 | },
34 | "languages" : ["af", "sq", "ar-sa", "ar-iq", "ar-eg", "ar-ly", "ar-dz", "ar-ma", "ar-tn", "ar-om", "ar-ye", "ar-sy", "ar-jo", "ar-lb", "ar-kw",
35 | "ar-ae", "ar-bh", "ar-qa", "eu", "bg", "be", "ca", "zh-tw", "zh-cn", "zh-hk", "zh-sg", "hr", "cs", "da", "nl", "nl-be", "en", "en-us",
36 | "en-gb", "en-au", "en-ca", "en-nz", "en-ie", "en-za", "en-jm", "en-bz", "en-tt", "et", "fo", "fa", "fi", "fr", "fr-be", "fr-ca",
37 | "fr-ch", "fr-lu", "gd", "gd-ie", "de", "de-ch", "de-at", "de-lu", "de-li", "el", "he", "hi", "hu", "is", "id", "it", "it-ch", "ja",
38 | "ko", "lv", "lt", "mk", "ms", "mt", "no", "pl", "pt-br", "pt-pt", "rm", "ro", "ro-mo", "ru", "ru-mo", "sz", "sr", "sk", "sl", "sb",
39 | "es", "es-ar", "es-gt", "es-cr", "es-pa", "es-do", "es-mx", "es-ve", "es-co", "es-pe", "es-ec", "es-cl", "es-uy", "es-py", "es-bo",
40 | "es-sv", "es-hn", "es-ni", "es-pr", "sx", "sv", "sv-fi", "th", "ts", "tn", "tr", "uk", "ur", "ve", "vi", "xh", "ji", "zu"],
41 | "http" : {
42 | "order" : ["Host", "Accept", "Accept-Language", "Accept-Encoding", "User-Agent"],
43 | "encoding" : "gzip, deflate"
44 | },
45 | "timezones" : [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270,
46 | -240, -210, -180, -120, -60, 0, 60, 120, 180, 210,
47 | 240, 270, 300, 330, 345, 360, 390, 420, 480, 525,
48 | 540, 570, 600, 630, 660, 690, 720, 765, 780, 840],
49 | "appcodename" : "Mozilla",
50 | "appname" : "Netscape",
51 | "product" : "Gecko",
52 | "vendor" : "Apple Computer, Inc."
53 | }
--------------------------------------------------------------------------------
/Plugin/skin/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/ajax-loader.gif
--------------------------------------------------------------------------------
/Plugin/skin/allow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/allow.png
--------------------------------------------------------------------------------
/Plugin/skin/block.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/block.png
--------------------------------------------------------------------------------
/Plugin/skin/cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/cancel.png
--------------------------------------------------------------------------------
/Plugin/skin/collapsed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/collapsed.png
--------------------------------------------------------------------------------
/Plugin/skin/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/error.png
--------------------------------------------------------------------------------
/Plugin/skin/expanded.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/expanded.png
--------------------------------------------------------------------------------
/Plugin/skin/facebook-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/facebook-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/facebook-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/facebook-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/flash-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/flash-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/flash-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/flash-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/googleplus-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/googleplus-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/googleplus-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/googleplus-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/help.png
--------------------------------------------------------------------------------
/Plugin/skin/icon32-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/icon32-disabled.png
--------------------------------------------------------------------------------
/Plugin/skin/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/icon32.png
--------------------------------------------------------------------------------
/Plugin/skin/icon64-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/icon64-disabled.png
--------------------------------------------------------------------------------
/Plugin/skin/icon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/icon64.png
--------------------------------------------------------------------------------
/Plugin/skin/linkedin-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/linkedin-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/linkedin-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/linkedin-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/logo.png
--------------------------------------------------------------------------------
/Plugin/skin/other-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/other-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/other-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/other-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/pinterest-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/pinterest-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/pinterest-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/pinterest-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/private-browsing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/private-browsing.png
--------------------------------------------------------------------------------
/Plugin/skin/quicktime-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/quicktime-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/quicktime-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/quicktime-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/settings.png
--------------------------------------------------------------------------------
/Plugin/skin/silverlight-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/silverlight-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/silverlight-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/silverlight-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/skin.css:
--------------------------------------------------------------------------------
1 | /****************************************************************/
2 | /* -- Fingerprint Privacy -- */
3 | /* Author: Christof Ferreira Torres */
4 | /* Date: 06.06.2014 */
5 | /****************************************************************/
6 |
7 | #fp-block-toolbar-button,
8 | window:not([active="true"]) #fp-block-toolbar-button,
9 | toolbar[iconsize="small"] #fp-block-toolbar-button {
10 | list-style-image: url("chrome://fpblock/skin/toolbar-icon.png");
11 | }
12 |
13 | #fp-block-toolbar-button .toolbarbutton-icon,
14 | window:not([active="true"]) #fp-block-toolbar-button .toolbarbutton-icon,
15 | toolbar[iconsize="small"] #fp-block-toolbar-button .toolbarbutton-icon {
16 | filter: none;
17 | opacity: 1.0;
18 | }
19 |
20 | #fp-block-toolbar-button[fpblockActivated="false"] .toolbarbutton-icon,
21 | window:not([active="true"]) #fp-block-toolbar-button[fpblockActivated="false"] .toolbarbutton-icon,
22 | toolbar[iconsize="small"] #fp-block-toolbar-button[fpblockActivated="false"] .toolbarbutton-icon {
23 | list-style-image: url("chrome://fpblock/skin/toolbar-disabled.png");
24 | }
25 |
26 | #fp-block-toolbar-button .toolbarbutton-icon {
27 | margin: 0px !important;
28 | width: auto !important;
29 | height: auto !important;
30 | }
31 |
32 | #fp-block-toolbar-button .toolbarbutton-menu-dropmarker {
33 | display: none;
34 | }
35 |
36 | #fpblock-popup {
37 | width: 206px;
38 | height: 276px;
39 | font-size: 11px;
40 | position: relative;
41 | background-color: #FFFFFF;
42 | }
43 |
44 | table {
45 | border-collapse: collapse;
46 | }
47 |
48 | #title {
49 | color: #2FCCFF;
50 | font-family: Tahoma, Geneva, sans-serif;
51 | font-weight: bold;
52 | font-size: 13px;
53 | padding: 0px 5px 0px 5px;
54 | width: 130px;
55 | }
56 |
57 | #domain {
58 | color: #A1A1A1;
59 | font-weight: bold;
60 | font-style: italic;
61 | padding: 0px 5px 0px 5px;
62 | }
63 |
64 | #private-browsing {
65 | width: 28px;
66 | height: 20px;
67 | padding-top: 8px;
68 | text-align: center;
69 | }
70 |
71 | #settings {
72 | width: 28px;
73 | height: 28px;
74 | cursor: pointer;
75 | text-align: center;
76 | }
77 |
78 | .caption {
79 | color: #A1A1A1;
80 | font-weight: bold;
81 | padding: 5px 5px 5px 5px;
82 | }
83 |
84 | #social-plugins {
85 | height: 60px;
86 | border-top: 1px solid #A1A1A1;
87 | }
88 |
89 | #social-plugins-table {
90 | text-align: center;
91 | }
92 |
93 | .plugins-logo {
94 | padding: 2px;
95 | text-align: center;
96 | }
97 |
98 | .button {
99 | width: 28px;
100 | height: 28px;
101 | cursor: pointer;
102 | }
103 |
104 | #summary {
105 | border-top: 1px solid #A1A1A1;
106 | }
107 |
108 | .summary-list-item {
109 | color: #A1A1A1;
110 | cursor: pointer;
111 | }
112 |
113 | .summary-list-item-label {
114 | width: 130px;
115 | padding-left: 10px;
116 | }
117 |
118 | .summary-list-item-number {
119 | width: 40px;
120 | text-align: right;
121 | }
122 |
123 | #attribute-list {
124 | display: none;
125 | }
126 |
127 | .attribute-checkbox {
128 | margin-left: 15px;
129 | }
130 |
131 | .attribute-label {
132 | color: #A1A1A1;
133 | padding-left: 10px;
134 | }
135 |
136 | #third-parties-list {
137 | display: none;
138 | }
139 |
140 | .third-party-checkbox {
141 | margin-left: 15px;
142 | }
143 |
144 | .third-party-label {
145 | color: #A1A1A1;
146 | padding-left: 10px;
147 | }
148 |
149 | #browser-plugins {
150 | border-top: 1px solid #A1A1A1;
151 | }
152 |
153 | #browser-plugins-table {
154 | text-align: center;
155 | }
156 |
157 | #domain-error {
158 | width: 206px;
159 | display: none;
160 | color: #A1A1A1;
161 | font-size: 12px;
162 | padding-top: 60px;
163 | text-align: center;
164 | text-decoration: bold;
165 | border-top: 1px solid #A1A1A1;
166 | }
167 |
168 | #website-switch {
169 | padding: 8px 20px 0px 20px;
170 | border-top: 1px solid #A1A1A1;
171 | }
172 |
173 | .error-message {
174 | color: #A1A1A1;
175 | }
176 |
177 | /***********************************/
178 | /* On/Off FlipSwitch from Proto.io */
179 | /* http://proto.io/freebies/onoff/ */
180 | /***********************************/
181 |
182 | .onoffswitch {
183 | position: relative; width: 167px;
184 | -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
185 | }
186 | .onoffswitch-checkbox {
187 | display: none;
188 | }
189 | .onoffswitch-label {
190 | display: block; overflow: hidden; cursor: pointer;
191 | border: 2px solid #FFFFFF; border-radius: 26px;
192 | }
193 | .onoffswitch-inner {
194 | width: 200%; margin-left: -100%;
195 | -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
196 | -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
197 | }
198 | .onoffswitch-inner:before, .onoffswitch-inner:after {
199 | float: left; width: 50%; height: 28px; padding: 0; line-height: 28px;
200 | font-size: 11px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
201 | -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
202 | }
203 | .onoffswitch-inner:before {
204 | content: "Disable for this website";
205 | padding-left: 9px;
206 | background-color: #EEEEEE; color: #2FCCFF;
207 | }
208 | .onoffswitch-inner:after {
209 | content: "Enable for this website";
210 | padding-right: 9px;
211 | background-color: #EEEEEE; color: #999999;
212 | text-align: right;
213 | }
214 | .onoffswitch-switch {
215 | width: 19px; margin: 4.5px;
216 | background: #A1A1A1;
217 | border: 2px solid #FFFFFF; border-radius: 26px;
218 | position: absolute; top: 0; bottom: 0; right: 135px;
219 | -moz-transition: all 0.3s ease-in 0s; -webkit-transition: all 0.3s ease-in 0s;
220 | -o-transition: all 0.3s ease-in 0s; transition: all 0.3s ease-in 0s;
221 | }
222 | .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
223 | margin-left: 0;
224 | }
225 | .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
226 | right: 0px;
227 | background-color: #2FCCFF;
228 | }
229 |
--------------------------------------------------------------------------------
/Plugin/skin/spoof.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/spoof.png
--------------------------------------------------------------------------------
/Plugin/skin/toolbar-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/toolbar-disabled.png
--------------------------------------------------------------------------------
/Plugin/skin/toolbar-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/toolbar-icon.png
--------------------------------------------------------------------------------
/Plugin/skin/tumblr-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/tumblr-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/tumblr-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/tumblr-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/twitter-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/twitter-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/twitter-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/twitter-blocked.png
--------------------------------------------------------------------------------
/Plugin/skin/vlc-allowed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/vlc-allowed.png
--------------------------------------------------------------------------------
/Plugin/skin/vlc-blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/christoftorres/FP-Block/982624e8a097b4737db79a841f3346c671e17602/Plugin/skin/vlc-blocked.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FP-Block
2 | Copyright (C) 2015 - Christof Torres
3 |
4 | License/usage:
5 | =========================
6 | This program is released under the terms of the GPL v3 license, a copy
7 | of which should be included with this distribution.
8 | This program is provided "AS IS", without any warranties of any kind,
9 | either expressed or implied.
10 |
11 |
12 |
13 | About
14 | =========================
15 | Online tracking is big business. Various companies are so widely used on
16 | the Web, that many (if not most) pages a casual user visits will embed
17 | their products. Examples include Facebook ('like' button), Youtube
18 | (videos), but also less visible aspects such as JQuery (popular
19 | Javascript library). Whenever a browser encounters such embedded
20 | contents, the embedded contents can determine the browser's
21 | "fingerprint" - a set of attribute values of the browser (resolution,
22 | language, OS, browser version, etc). As such, they can track a browser
23 | across each and every page where they are embedded.
24 |
25 | The FP-Block Firefox plugin ensures that each visited website is
26 | provided with a unique fingerprint. This ensures that all embedded
27 | parties also see that unique fingerprint, and thus no longer can track
28 | users across different websites.
29 |
30 |
31 |
32 |
33 | Installation instructions
34 | =========================
35 |
36 | 1. Compile the source
37 | 2. Install the plugin
38 |
39 | Compile the source
40 | ------------------
41 |
42 | **Windows:**
43 |
44 | Select the "Plugin" folder, do a right-click and choose:
45 | Send To -> Compressed (Zipped) Folder
46 | Afterwards you simply rename the resulting ZIP file to .xpi
47 | instead of .zip. Done!
48 |
49 | **Mac & Linux:**
50 |
51 | In order to "compile" the source code to a Firefox extension,
52 | you only need to run the file "Makefile" or manually run the
53 | following command inside the console:
54 |
55 | Mac
56 | zip -r ../FP-Block.xpi * -x *.DS Store*
57 |
58 | Linux
59 | zip -r ../FP-Block.xpi *
60 |
61 | Install the plugin
62 | ------------------
63 | To install the plugin, just drag and drop the FP-Block.xpi
64 | file onto Firefox. A popup window will appear asking to install. Click
65 | "Install" and restart Firefox. Enjoy!
66 |
--------------------------------------------------------------------------------