toolkit/components/downloads/test/unit/test_app_rep.js

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:a2153e064de0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 Cu.import('resource://gre/modules/NetUtil.jsm');
8 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
9
10 const gAppRep = Cc["@mozilla.org/downloads/application-reputation-service;1"].
11 getService(Ci.nsIApplicationReputationService);
12 let gHttpServ = null;
13 let gTables = {};
14
15 let ALLOW_LIST = 0;
16 let BLOCK_LIST = 1;
17 let NO_LIST = 2;
18
19 function readFileToString(aFilename) {
20 let f = do_get_file(aFilename);
21 let stream = Cc["@mozilla.org/network/file-input-stream;1"]
22 .createInstance(Ci.nsIFileInputStream);
23 stream.init(f, -1, 0, 0);
24 let buf = NetUtil.readInputStreamToString(stream, stream.available());
25 return buf;
26 }
27
28 // Registers a table for which to serve update chunks. Returns a promise that
29 // resolves when that chunk has been downloaded.
30 function registerTableUpdate(aTable, aFilename) {
31 // If we haven't been given an update for this table yet, add it to the map
32 if (!(aTable in gTables)) {
33 gTables[aTable] = [];
34 }
35
36 // The number of chunks associated with this table.
37 let numChunks = gTables[aTable].length + 1;
38 let redirectPath = "/" + aTable + "-" + numChunks;
39 let redirectUrl = "localhost:4444" + redirectPath;
40
41 // Store redirect url for that table so we can return it later when we
42 // process an update request.
43 gTables[aTable].push(redirectUrl);
44
45 gHttpServ.registerPathHandler(redirectPath, function(request, response) {
46 do_print("Mock safebrowsing server handling request for " + redirectPath);
47 let contents = readFileToString(aFilename);
48 do_print("Length of " + aFilename + ": " + contents.length);
49 response.setHeader("Content-Type",
50 "application/vnd.google.safebrowsing-update", false);
51 response.setStatusLine(request.httpVersion, 200, "OK");
52 response.bodyOutputStream.write(contents, contents.length);
53 });
54 }
55
56 function run_test() {
57 // Set up a local HTTP server to return bad verdicts.
58 Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
59 "http://localhost:4444/download");
60 // Ensure safebrowsing is enabled for this test, even if the app
61 // doesn't have it enabled.
62 Services.prefs.setBoolPref("browser.safebrowsing.malware.enabled", true);
63 do_register_cleanup(function() {
64 Services.prefs.clearUserPref("browser.safebrowsing.malware.enabled");
65 });
66
67 // Set download_block_table explicitly.
68 Services.prefs.setCharPref("urlclassifier.downloadBlockTable",
69 "goog-badbinurl-shavar");
70 do_register_cleanup(function() {
71 Services.prefs.clearUserPref("urlclassifier.downloadBlockTable");
72 });
73
74 gHttpServ = new HttpServer();
75 gHttpServ.registerDirectory("/", do_get_cwd());
76 gHttpServ.registerPathHandler("/download", function(request, response) {
77 do_throw("This test should never make a remote lookup");
78 });
79 gHttpServ.start(4444);
80
81 run_next_test();
82 }
83
84 function check_telemetry(aCount,
85 aShouldBlockCount,
86 aListCounts) {
87 let count = Cc["@mozilla.org/base/telemetry;1"]
88 .getService(Ci.nsITelemetry)
89 .getHistogramById("APPLICATION_REPUTATION_COUNT")
90 .snapshot();
91 do_check_eq(count.counts[1], aCount);
92 let local = Cc["@mozilla.org/base/telemetry;1"]
93 .getService(Ci.nsITelemetry)
94 .getHistogramById("APPLICATION_REPUTATION_LOCAL")
95 .snapshot();
96 do_check_eq(local.counts[ALLOW_LIST], aListCounts[ALLOW_LIST]);
97 do_check_eq(local.counts[BLOCK_LIST], aListCounts[BLOCK_LIST]);
98 do_check_eq(local.counts[NO_LIST], aListCounts[NO_LIST]);
99 let shouldBlock = Cc["@mozilla.org/base/telemetry;1"]
100 .getService(Ci.nsITelemetry)
101 .getHistogramById("APPLICATION_REPUTATION_SHOULD_BLOCK")
102 .snapshot();
103 // SHOULD_BLOCK = true
104 do_check_eq(shouldBlock.counts[1], aShouldBlockCount);
105 // Sanity check that SHOULD_BLOCK total adds up to the COUNT.
106 do_check_eq(shouldBlock.counts[0] + shouldBlock.counts[1], aCount);
107 }
108
109 function get_telemetry_counts() {
110 let count = Cc["@mozilla.org/base/telemetry;1"]
111 .getService(Ci.nsITelemetry)
112 .getHistogramById("APPLICATION_REPUTATION_COUNT")
113 .snapshot();
114 let local = Cc["@mozilla.org/base/telemetry;1"]
115 .getService(Ci.nsITelemetry)
116 .getHistogramById("APPLICATION_REPUTATION_LOCAL")
117 .snapshot();
118 let shouldBlock = Cc["@mozilla.org/base/telemetry;1"]
119 .getService(Ci.nsITelemetry)
120 .getHistogramById("APPLICATION_REPUTATION_SHOULD_BLOCK")
121 .snapshot();
122 return { total: count.counts[1],
123 shouldBlock: shouldBlock.counts[1],
124 listCounts: local.counts };
125 }
126
127 add_test(function test_nullSourceURI() {
128 let counts = get_telemetry_counts();
129 gAppRep.queryReputation({
130 // No source URI
131 fileSize: 12,
132 }, function onComplete(aShouldBlock, aStatus) {
133 do_check_eq(Cr.NS_ERROR_UNEXPECTED, aStatus);
134 do_check_false(aShouldBlock);
135 check_telemetry(counts.total + 1, counts.shouldBlock, counts.listCounts);
136 run_next_test();
137 });
138 });
139
140 add_test(function test_nullCallback() {
141 let counts = get_telemetry_counts();
142 try {
143 gAppRep.queryReputation({
144 sourceURI: createURI("http://example.com"),
145 fileSize: 12,
146 }, null);
147 do_throw("Callback cannot be null");
148 } catch (ex if ex.result == Cr.NS_ERROR_INVALID_POINTER) {
149 // We don't even increment the count here, because there's no callback.
150 check_telemetry(counts.total, counts.shouldBlock, counts.listCounts);
151 run_next_test();
152 }
153 });
154
155 add_test(function test_disabled() {
156 let counts = get_telemetry_counts();
157 Services.prefs.setCharPref("browser.safebrowsing.appRepURL", "");
158 gAppRep.queryReputation({
159 sourceURI: createURI("http://example.com"),
160 fileSize: 12,
161 }, function onComplete(aShouldBlock, aStatus) {
162 // We should be getting NS_ERROR_NOT_AVAILABLE if the service is disabled
163 do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus);
164 do_check_false(aShouldBlock);
165 check_telemetry(counts.total + 1, counts.shouldBlock, counts.listCounts);
166 run_next_test();
167 });
168 });
169
170 // Set up the local whitelist.
171 add_test(function test_local_list() {
172 // Construct a response with redirect urls.
173 function processUpdateRequest() {
174 let response = "n:1000\n";
175 for (let table in gTables) {
176 response += "i:" + table + "\n";
177 for (let i = 0; i < gTables[table].length; ++i) {
178 response += "u:" + gTables[table][i] + "\n";
179 }
180 }
181 do_print("Returning update response: " + response);
182 return response;
183 }
184 gHttpServ.registerPathHandler("/downloads", function(request, response) {
185 let buf = NetUtil.readInputStreamToString(request.bodyInputStream,
186 request.bodyInputStream.available());
187 let blob = processUpdateRequest();
188 response.setHeader("Content-Type",
189 "application/vnd.google.safebrowsing-update", false);
190 response.setStatusLine(request.httpVersion, 200, "OK");
191 response.bodyOutputStream.write(blob, blob.length);
192 });
193
194 let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
195 .getService(Ci.nsIUrlClassifierStreamUpdater);
196 streamUpdater.updateUrl = "http://localhost:4444/downloads";
197
198 // Load up some update chunks for the safebrowsing server to serve.
199 // This chunk contains the hash of whitelisted.com/.
200 registerTableUpdate("goog-badbinurl-shavar", "data/block_digest.chunk");
201 // This chunk contains the hash of blocklisted.com/.
202 registerTableUpdate("goog-downloadwhite-digest256", "data/digest.chunk");
203
204 // Download some updates, and don't continue until the downloads are done.
205 function updateSuccess(aEvent) {
206 // Timeout of n:1000 is constructed in processUpdateRequest above and
207 // passed back in the callback in nsIUrlClassifierStreamUpdater on success.
208 do_check_eq("1000", aEvent);
209 do_print("All data processed");
210 run_next_test();
211 }
212 // Just throw if we ever get an update or download error.
213 function handleError(aEvent) {
214 do_throw("We didn't download or update correctly: " + aEvent);
215 }
216 streamUpdater.downloadUpdates(
217 "goog-downloadwhite-digest256,goog-badbinurl-shavar",
218 "goog-downloadwhite-digest256,goog-badbinurl-shavar;\n",
219 updateSuccess, handleError, handleError);
220 });
221
222 add_test(function test_unlisted() {
223 Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
224 "http://localhost:4444/download");
225 let counts = get_telemetry_counts();
226 let listCounts = counts.listCounts;
227 listCounts[NO_LIST]++;
228 gAppRep.queryReputation({
229 sourceURI: createURI("http://example.com"),
230 fileSize: 12,
231 }, function onComplete(aShouldBlock, aStatus) {
232 do_check_eq(Cr.NS_OK, aStatus);
233 do_check_false(aShouldBlock);
234 check_telemetry(counts.total + 1, counts.shouldBlock, listCounts);
235 run_next_test();
236 });
237 });
238
239 add_test(function test_local_blacklist() {
240 Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
241 "http://localhost:4444/download");
242 let counts = get_telemetry_counts();
243 let listCounts = counts.listCounts;
244 listCounts[BLOCK_LIST]++;
245 gAppRep.queryReputation({
246 sourceURI: createURI("http://blocklisted.com"),
247 fileSize: 12,
248 }, function onComplete(aShouldBlock, aStatus) {
249 do_check_eq(Cr.NS_OK, aStatus);
250 do_check_true(aShouldBlock);
251 check_telemetry(counts.total + 1, counts.shouldBlock + 1, listCounts);
252 run_next_test();
253 });
254 });
255
256 add_test(function test_referer_blacklist() {
257 Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
258 "http://localhost:4444/download");
259 let counts = get_telemetry_counts();
260 let listCounts = counts.listCounts;
261 listCounts[BLOCK_LIST]++;
262 gAppRep.queryReputation({
263 sourceURI: createURI("http://example.com"),
264 referrerURI: createURI("http://blocklisted.com"),
265 fileSize: 12,
266 }, function onComplete(aShouldBlock, aStatus) {
267 do_check_eq(Cr.NS_OK, aStatus);
268 do_check_true(aShouldBlock);
269 check_telemetry(counts.total + 1, counts.shouldBlock + 1, listCounts);
270 run_next_test();
271 });
272 });
273
274 add_test(function test_blocklist_trumps_allowlist() {
275 Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
276 "http://localhost:4444/download");
277 let counts = get_telemetry_counts();
278 let listCounts = counts.listCounts;
279 listCounts[BLOCK_LIST]++;
280 gAppRep.queryReputation({
281 sourceURI: createURI("http://whitelisted.com"),
282 referrerURI: createURI("http://blocklisted.com"),
283 fileSize: 12,
284 }, function onComplete(aShouldBlock, aStatus) {
285 do_check_eq(Cr.NS_OK, aStatus);
286 do_check_true(aShouldBlock);
287 check_telemetry(counts.total + 1, counts.shouldBlock + 1, listCounts);
288 run_next_test();
289 });
290 });

mercurial