toolkit/components/url-classifier/tests/unit/head_urlclassifier.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 //* -*- Mode: Javascript; tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*- *
michael@0 2 function dumpn(s) {
michael@0 3 dump(s + "\n");
michael@0 4 }
michael@0 5
michael@0 6 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
michael@0 7 const NS_APP_USER_PROFILE_LOCAL_50_DIR = "ProfLD";
michael@0 8
michael@0 9 const Cc = Components.classes;
michael@0 10 const Ci = Components.interfaces;
michael@0 11 const Cu = Components.utils;
michael@0 12 const Cr = Components.results;
michael@0 13
michael@0 14 Cu.import("resource://testing-common/httpd.js");
michael@0 15
michael@0 16 do_get_profile();
michael@0 17
michael@0 18 var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
michael@0 19
michael@0 20 var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
michael@0 21
michael@0 22 var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
michael@0 23 .getService(Ci.nsIScriptSecurityManager);
michael@0 24
michael@0 25 // Disable hashcompleter noise for tests
michael@0 26 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
michael@0 27 getService(Ci.nsIPrefBranch);
michael@0 28 prefBranch.setIntPref("urlclassifier.gethashnoise", 0);
michael@0 29
michael@0 30 // Enable malware/phishing checking for tests
michael@0 31 prefBranch.setBoolPref("browser.safebrowsing.malware.enabled", true);
michael@0 32 prefBranch.setBoolPref("browser.safebrowsing.enabled", true);
michael@0 33
michael@0 34 // Enable all completions for tests
michael@0 35 prefBranch.setCharPref("urlclassifier.disallow_completions", "");
michael@0 36
michael@0 37 function delFile(name) {
michael@0 38 try {
michael@0 39 // Delete a previously created sqlite file
michael@0 40 var file = dirSvc.get('ProfLD', Ci.nsIFile);
michael@0 41 file.append(name);
michael@0 42 if (file.exists())
michael@0 43 file.remove(false);
michael@0 44 } catch(e) {
michael@0 45 }
michael@0 46 }
michael@0 47
michael@0 48 function cleanUp() {
michael@0 49 delFile("urlclassifier3.sqlite");
michael@0 50 delFile("safebrowsing/classifier.hashkey");
michael@0 51 delFile("safebrowsing/test-phish-simple.sbstore");
michael@0 52 delFile("safebrowsing/test-malware-simple.sbstore");
michael@0 53 delFile("safebrowsing/test-phish-simple.cache");
michael@0 54 delFile("safebrowsing/test-malware-simple.cache");
michael@0 55 delFile("safebrowsing/test-phish-simple.pset");
michael@0 56 delFile("safebrowsing/test-malware-simple.pset");
michael@0 57 }
michael@0 58
michael@0 59 var allTables = "test-phish-simple,test-malware-simple";
michael@0 60
michael@0 61 var dbservice = Cc["@mozilla.org/url-classifier/dbservice;1"].getService(Ci.nsIUrlClassifierDBService);
michael@0 62 var streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
michael@0 63 .getService(Ci.nsIUrlClassifierStreamUpdater);
michael@0 64
michael@0 65
michael@0 66 /*
michael@0 67 * Builds an update from an object that looks like:
michael@0 68 *{ "test-phish-simple" : [{
michael@0 69 * "chunkType" : "a", // 'a' is assumed if not specified
michael@0 70 * "chunkNum" : 1, // numerically-increasing chunk numbers are assumed
michael@0 71 * // if not specified
michael@0 72 * "urls" : [ "foo.com/a", "foo.com/b", "bar.com/" ]
michael@0 73 * }
michael@0 74 */
michael@0 75
michael@0 76 function buildUpdate(update, hashSize) {
michael@0 77 if (!hashSize) {
michael@0 78 hashSize = 32;
michael@0 79 }
michael@0 80 var updateStr = "n:1000\n";
michael@0 81
michael@0 82 for (var tableName in update) {
michael@0 83 if (tableName != "")
michael@0 84 updateStr += "i:" + tableName + "\n";
michael@0 85 var chunks = update[tableName];
michael@0 86 for (var j = 0; j < chunks.length; j++) {
michael@0 87 var chunk = chunks[j];
michael@0 88 var chunkType = chunk.chunkType ? chunk.chunkType : 'a';
michael@0 89 var chunkNum = chunk.chunkNum ? chunk.chunkNum : j;
michael@0 90 updateStr += chunkType + ':' + chunkNum + ':' + hashSize;
michael@0 91
michael@0 92 if (chunk.urls) {
michael@0 93 var chunkData = chunk.urls.join("\n");
michael@0 94 updateStr += ":" + chunkData.length + "\n" + chunkData;
michael@0 95 }
michael@0 96
michael@0 97 updateStr += "\n";
michael@0 98 }
michael@0 99 }
michael@0 100
michael@0 101 return updateStr;
michael@0 102 }
michael@0 103
michael@0 104 function buildPhishingUpdate(chunks, hashSize) {
michael@0 105 return buildUpdate({"test-phish-simple" : chunks}, hashSize);
michael@0 106 }
michael@0 107
michael@0 108 function buildMalwareUpdate(chunks, hashSize) {
michael@0 109 return buildUpdate({"test-malware-simple" : chunks}, hashSize);
michael@0 110 }
michael@0 111
michael@0 112 function buildBareUpdate(chunks, hashSize) {
michael@0 113 return buildUpdate({"" : chunks}, hashSize);
michael@0 114 }
michael@0 115
michael@0 116 /**
michael@0 117 * Performs an update of the dbservice manually, bypassing the stream updater
michael@0 118 */
michael@0 119 function doSimpleUpdate(updateText, success, failure) {
michael@0 120 var listener = {
michael@0 121 QueryInterface: function(iid)
michael@0 122 {
michael@0 123 if (iid.equals(Ci.nsISupports) ||
michael@0 124 iid.equals(Ci.nsIUrlClassifierUpdateObserver))
michael@0 125 return this;
michael@0 126 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 127 },
michael@0 128
michael@0 129 updateUrlRequested: function(url) { },
michael@0 130 streamFinished: function(status) { },
michael@0 131 updateError: function(errorCode) { failure(errorCode); },
michael@0 132 updateSuccess: function(requestedTimeout) { success(requestedTimeout); }
michael@0 133 };
michael@0 134
michael@0 135 dbservice.beginUpdate(listener,
michael@0 136 "test-phish-simple,test-malware-simple");
michael@0 137 dbservice.beginStream("", "");
michael@0 138 dbservice.updateStream(updateText);
michael@0 139 dbservice.finishStream();
michael@0 140 dbservice.finishUpdate();
michael@0 141 }
michael@0 142
michael@0 143 /**
michael@0 144 * Simulates a failed database update.
michael@0 145 */
michael@0 146 function doErrorUpdate(tables, success, failure) {
michael@0 147 var listener = {
michael@0 148 QueryInterface: function(iid)
michael@0 149 {
michael@0 150 if (iid.equals(Ci.nsISupports) ||
michael@0 151 iid.equals(Ci.nsIUrlClassifierUpdateObserver))
michael@0 152 return this;
michael@0 153 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 154 },
michael@0 155
michael@0 156 updateUrlRequested: function(url) { },
michael@0 157 streamFinished: function(status) { },
michael@0 158 updateError: function(errorCode) { success(errorCode); },
michael@0 159 updateSuccess: function(requestedTimeout) { failure(requestedTimeout); }
michael@0 160 };
michael@0 161
michael@0 162 dbservice.beginUpdate(listener, tables, null);
michael@0 163 dbservice.beginStream("", "");
michael@0 164 dbservice.cancelUpdate();
michael@0 165 }
michael@0 166
michael@0 167 /**
michael@0 168 * Performs an update of the dbservice using the stream updater and a
michael@0 169 * data: uri
michael@0 170 */
michael@0 171 function doStreamUpdate(updateText, success, failure, downloadFailure) {
michael@0 172 var dataUpdate = "data:," + encodeURIComponent(updateText);
michael@0 173
michael@0 174 if (!downloadFailure)
michael@0 175 downloadFailure = failure;
michael@0 176
michael@0 177 streamUpdater.updateUrl = dataUpdate;
michael@0 178 streamUpdater.downloadUpdates("test-phish-simple,test-malware-simple", "",
michael@0 179 success, failure, downloadFailure);
michael@0 180 }
michael@0 181
michael@0 182 var gAssertions = {
michael@0 183
michael@0 184 tableData : function(expectedTables, cb)
michael@0 185 {
michael@0 186 dbservice.getTables(function(tables) {
michael@0 187 // rebuild the tables in a predictable order.
michael@0 188 var parts = tables.split("\n");
michael@0 189 while (parts[parts.length - 1] == '') {
michael@0 190 parts.pop();
michael@0 191 }
michael@0 192 parts.sort();
michael@0 193 tables = parts.join("\n");
michael@0 194
michael@0 195 do_check_eq(tables, expectedTables);
michael@0 196 cb();
michael@0 197 });
michael@0 198 },
michael@0 199
michael@0 200 checkUrls: function(urls, expected, cb)
michael@0 201 {
michael@0 202 // work with a copy of the list.
michael@0 203 urls = urls.slice(0);
michael@0 204 var doLookup = function() {
michael@0 205 if (urls.length > 0) {
michael@0 206 var fragment = urls.shift();
michael@0 207 var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("http://" + fragment, null, null));
michael@0 208 dbservice.lookup(principal, allTables,
michael@0 209 function(arg) {
michael@0 210 do_check_eq(expected, arg);
michael@0 211 doLookup();
michael@0 212 }, true);
michael@0 213 } else {
michael@0 214 cb();
michael@0 215 }
michael@0 216 };
michael@0 217 doLookup();
michael@0 218 },
michael@0 219
michael@0 220 urlsDontExist: function(urls, cb)
michael@0 221 {
michael@0 222 this.checkUrls(urls, '', cb);
michael@0 223 },
michael@0 224
michael@0 225 urlsExist: function(urls, cb)
michael@0 226 {
michael@0 227 this.checkUrls(urls, 'test-phish-simple', cb);
michael@0 228 },
michael@0 229
michael@0 230 malwareUrlsExist: function(urls, cb)
michael@0 231 {
michael@0 232 this.checkUrls(urls, 'test-malware-simple', cb);
michael@0 233 },
michael@0 234
michael@0 235 subsDontExist: function(urls, cb)
michael@0 236 {
michael@0 237 // XXX: there's no interface for checking items in the subs table
michael@0 238 cb();
michael@0 239 },
michael@0 240
michael@0 241 subsExist: function(urls, cb)
michael@0 242 {
michael@0 243 // XXX: there's no interface for checking items in the subs table
michael@0 244 cb();
michael@0 245 }
michael@0 246
michael@0 247 };
michael@0 248
michael@0 249 /**
michael@0 250 * Check a set of assertions against the gAssertions table.
michael@0 251 */
michael@0 252 function checkAssertions(assertions, doneCallback)
michael@0 253 {
michael@0 254 var checkAssertion = function() {
michael@0 255 for (var i in assertions) {
michael@0 256 var data = assertions[i];
michael@0 257 delete assertions[i];
michael@0 258 gAssertions[i](data, checkAssertion);
michael@0 259 return;
michael@0 260 }
michael@0 261
michael@0 262 doneCallback();
michael@0 263 }
michael@0 264
michael@0 265 checkAssertion();
michael@0 266 }
michael@0 267
michael@0 268 function updateError(arg)
michael@0 269 {
michael@0 270 do_throw(arg);
michael@0 271 }
michael@0 272
michael@0 273 // Runs a set of updates, and then checks a set of assertions.
michael@0 274 function doUpdateTest(updates, assertions, successCallback, errorCallback) {
michael@0 275 var errorUpdate = function() {
michael@0 276 checkAssertions(assertions, errorCallback);
michael@0 277 }
michael@0 278
michael@0 279 var runUpdate = function() {
michael@0 280 if (updates.length > 0) {
michael@0 281 var update = updates.shift();
michael@0 282 doStreamUpdate(update, runUpdate, errorUpdate, null);
michael@0 283 } else {
michael@0 284 checkAssertions(assertions, successCallback);
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 runUpdate();
michael@0 289 }
michael@0 290
michael@0 291 var gTests;
michael@0 292 var gNextTest = 0;
michael@0 293
michael@0 294 function runNextTest()
michael@0 295 {
michael@0 296 if (gNextTest >= gTests.length) {
michael@0 297 do_test_finished();
michael@0 298 return;
michael@0 299 }
michael@0 300
michael@0 301 dbservice.resetDatabase();
michael@0 302 dbservice.setHashCompleter('test-phish-simple', null);
michael@0 303
michael@0 304 let test = gTests[gNextTest++];
michael@0 305 dump("running " + test.name + "\n");
michael@0 306 test();
michael@0 307 }
michael@0 308
michael@0 309 function runTests(tests)
michael@0 310 {
michael@0 311 gTests = tests;
michael@0 312 runNextTest();
michael@0 313 }
michael@0 314
michael@0 315 var timerArray = [];
michael@0 316
michael@0 317 function Timer(delay, cb) {
michael@0 318 this.cb = cb;
michael@0 319 var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
michael@0 320 timer.initWithCallback(this, delay, timer.TYPE_ONE_SHOT);
michael@0 321 timerArray.push(timer);
michael@0 322 }
michael@0 323
michael@0 324 Timer.prototype = {
michael@0 325 QueryInterface: function(iid) {
michael@0 326 if (!iid.equals(Ci.nsISupports) && !iid.equals(Ci.nsITimerCallback)) {
michael@0 327 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 328 }
michael@0 329 return this;
michael@0 330 },
michael@0 331 notify: function(timer) {
michael@0 332 this.cb();
michael@0 333 }
michael@0 334 }
michael@0 335
michael@0 336 // LFSRgenerator is a 32-bit linear feedback shift register random number
michael@0 337 // generator. It is highly predictable and is not intended to be used for
michael@0 338 // cryptography but rather to allow easier debugging than a test that uses
michael@0 339 // Math.random().
michael@0 340 function LFSRgenerator(seed) {
michael@0 341 // Force |seed| to be a number.
michael@0 342 seed = +seed;
michael@0 343 // LFSR generators do not work with a value of 0.
michael@0 344 if (seed == 0)
michael@0 345 seed = 1;
michael@0 346
michael@0 347 this._value = seed;
michael@0 348 }
michael@0 349 LFSRgenerator.prototype = {
michael@0 350 // nextNum returns a random unsigned integer of in the range [0,2^|bits|].
michael@0 351 nextNum: function(bits) {
michael@0 352 if (!bits)
michael@0 353 bits = 32;
michael@0 354
michael@0 355 let val = this._value;
michael@0 356 // Taps are 32, 22, 2 and 1.
michael@0 357 let bit = ((val >>> 0) ^ (val >>> 10) ^ (val >>> 30) ^ (val >>> 31)) & 1;
michael@0 358 val = (val >>> 1) | (bit << 31);
michael@0 359 this._value = val;
michael@0 360
michael@0 361 return (val >>> (32 - bits));
michael@0 362 },
michael@0 363 };
michael@0 364
michael@0 365 cleanUp();

mercurial