home *** CD-ROM | disk | FTP | other *** search
/ Minami 81 / MINAMI81.ISO / Extra / DivXInstaller.exe / $PLUGINSDIR / GoogleToolbarFirefox.msi / xpi / amulet-jslib / listmanager.js < prev    next >
Text File  |  2006-05-15  |  15KB  |  492 lines

  1. function PROT_ListManager(opt_testing) {
  2. this.debugZone = "listmanager";
  3. if (opt_testing)
  4. this.debugZone += "testing";
  5. G_debugService.enableZone(this.debugZone);
  6. this.testing_ = !!opt_testing;
  7. this.currentUpdateChecker_ = null;   // set when we toggle updates
  8. this.rpcPending_ = false;
  9. var self = this;
  10. this.updateserverURL_ = PROT_globalStore.getUpdateserverURL();
  11. this.tablesKnown_ = {};
  12. if (this.testing_) {
  13. this.tablesKnown_ = {
  14. "test1-foo-domain": new PROT_VersionParser("test1-foo-domain", 0, -1),
  15. "test2-foo-domain": new PROT_VersionParser("test2-foo-domain", 0, -1),
  16. "test-white-domain": new PROT_VersionParser("test-white-domain", 0, -1,
  17. true /* require mac*/),
  18. "test-mac-domain": new PROT_VersionParser("test-mac-domain", 0, -1,
  19. true /* require mac */)
  20. };
  21. }
  22. this.tablesData_ = {};
  23. this.registrar_ = new EventRegistrar({});
  24. this.urlCrypto_ = null;
  25. this.prefs_ = new G_Preferences();
  26. }
  27. PROT_ListManager.prototype.registerTable = function(tableName,
  28. opt_requireMac,
  29. opt_callback) {
  30. var table = new PROT_VersionParser(tableName, 1, -1, opt_requireMac);
  31. this.tablesKnown_[tableName] = table;
  32. this.tablesData_[tableName] = new PROT_TRTable(tableName);
  33. if (opt_callback) {
  34. if (!this.registrar_.isKnownEventType(tableName))
  35. this.registrar_.addEventType(tableName);
  36. this.registrar_.registerListener(tableName, opt_callback);
  37. G_Debug(this, "registering callback for " + tableName);
  38. }
  39. return true;
  40. }
  41. PROT_ListManager.prototype.enableUpdateTables = function(tables) {
  42. var changed = false;
  43. for (var i = 0; i < tables.length; ++i) {
  44. var table = this.tablesKnown_[tables[i]];
  45. if (table) {
  46. G_Debug(this, "Enabling table updates for " + tables[i]);
  47. table.needsUpdate = true;
  48. changed = true;
  49. }
  50. }
  51. if (changed === true)
  52. this.maybeToggleUpdateChecking();
  53. }
  54. PROT_ListManager.prototype.disableUpdateTables = function(tables) {
  55. var changed = false;
  56. for (var i = 0; i < tables.length; ++i) {
  57. var table = this.tablesKnown_[tables[i]];
  58. if (table) {
  59. G_Debug(this, "Disabling table updates for " + tables[i]);
  60. table.needsUpdate = false;
  61. changed = true;
  62. }
  63. }
  64. if (changed === true)
  65. this.maybeToggleUpdateChecking();
  66. }
  67. PROT_ListManager.prototype.requireTableUpdates = function() {
  68. for (var type in this.tablesKnown_) {
  69. if (this.tablesKnown_[type].major == 0)
  70. continue;
  71. if (this.tablesKnown_[type].needsUpdate)
  72. return true;
  73. }
  74. return false;
  75. }
  76. PROT_ListManager.prototype.maybeStartManagingUpdates = function() {
  77. if (this.testing_)
  78. return;
  79. this.maybeToggleUpdateChecking();
  80. }
  81. PROT_ListManager.prototype.maybeToggleUpdateChecking = function() {
  82. if (this.testing_)
  83. return;
  84. if (this.requireTableUpdates() === true) {
  85. G_Debug(this, "Starting managing lists");
  86. this.loadTableVersions_();
  87. if (!this.currentUpdateChecker_)
  88. this.currentUpdateChecker_ =
  89. new G_Alarm(BindToObject(this.checkForUpdates, this), 3000);
  90. this.startUpdateChecker();
  91. } else {
  92. G_Debug(this, "Stopping managing lists (if currently active)");
  93. this.stopUpdateChecker();                    // Cancel pending updates
  94. }
  95. }
  96. PROT_ListManager.prototype.startUpdateChecker = function() {
  97. this.stopUpdateChecker();
  98. var thirtyMinutes = 30 * 60 * 1000;
  99. this.updateChecker_ = new G_Alarm(BindToObject(this.checkForUpdates, this),
  100. thirtyMinutes, true /* repeat */);
  101. }
  102. PROT_ListManager.prototype.stopUpdateChecker = function() {
  103. if (this.updateChecker_) {
  104. this.updateChecker_.cancel();
  105. this.updateChecker_ = null;
  106. }
  107. }
  108. PROT_ListManager.prototype.safeLookup = function(table, key) {
  109. var result = false;
  110. try {
  111. var map = this.tablesData_[table];
  112. result = map.find(key);
  113. } catch(e) {
  114. result = false;
  115. G_Debug(this, "Safelookup masked failure for " + table + ", key " + key + ": " + e);
  116. }
  117. return result;
  118. }
  119. PROT_ListManager.prototype.safeInsert = function(table, key, value) {
  120. if (!this.tablesKnown_[table]) {
  121. G_Debug(this, "Unknown table: " + table);
  122. return false;
  123. }
  124. if (!this.tablesData_[table])
  125. this.tablesData_[table] = new PROT_TRTable(table);
  126. try {
  127. this.tablesData_[table].insert(key, value);
  128. } catch (e) {
  129. G_Debug(this, "Cannot insert key " + key + " value " + value);
  130. G_Debug(this, e);
  131. return false;
  132. }
  133. return true;
  134. }
  135. PROT_ListManager.prototype.safeErase = function(table, key) {
  136. if (!this.tablesKnown_[table]) {
  137. G_Debug(this, "Unknown table: " + table);
  138. return false;
  139. }
  140. if (!this.tablesData_[table])
  141. return false;
  142. return this.tablesData_[table].erase(key);
  143. }
  144. PROT_ListManager.prototype.loadTableVersions_ = function() {
  145. var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
  146. for (var table in this.tablesKnown_) {
  147. var version = this.prefs_.getPref(prefBase + table, "1.-1");
  148. G_Debug(this, "loadTableVersion " + table + ": " + version);
  149. var tokens = version.split(".");
  150. G_Assert(this, tokens.length == 2, "invalid version number");
  151. this.tablesKnown_[table].major = tokens[0];
  152. this.tablesKnown_[table].minor = tokens[1];
  153. }
  154. }
  155. PROT_ListManager.prototype.setTableVersions_ = function(updateString) {
  156. var updatedTables = [];
  157. var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
  158. var startPos = updateString.indexOf('[');
  159. var endPos;
  160. while (startPos != -1) {
  161. if (0 == startPos || ('\n' == updateString[startPos - 1] &&
  162. '\n' == updateString[startPos - 2])) {
  163. endPos = updateString.indexOf('\n', startPos);
  164. if (endPos != -1) {
  165. var line = updateString.substring(startPos, endPos);
  166. var versionParser = new PROT_VersionParser("dummy");
  167. if (versionParser.fromString(line)) {
  168. var tableName = versionParser.type;
  169. var version = versionParser.major + '.' + versionParser.minor;
  170. G_Debug(this, "Set table version for " + tableName + ": " + version);
  171. this.prefs_.setPref(prefBase + tableName, version);
  172. this.tablesKnown_[tableName].ImportVersion(versionParser);
  173. updatedTables.push(tableName);
  174. }
  175. }
  176. }
  177. startPos = updateString.indexOf('[', startPos + 1);
  178. }
  179. return updatedTables;
  180. }
  181. PROT_ListManager.prototype.getRequestURL_ = function(url) {
  182. url += "version=";
  183. var firstElement = true;
  184. var requestMac = false;
  185. for (var type in this.tablesKnown_) {
  186. if (this.tablesKnown_[type].major == 0)
  187. continue;
  188. if (this.tablesKnown_[type].needsUpdate == false)
  189. continue;
  190. if (!firstElement) {
  191. url += ","
  192. } else {
  193. firstElement = false;
  194. }
  195. url += type + ":" + this.tablesKnown_[type].toUrl();
  196. if (this.tablesKnown_[type].requireMac)
  197. requestMac = true;
  198. }
  199. if (requestMac) {
  200. if (!this.urlCrypto_)
  201. this.urlCrypto_ = new PROT_UrlCrypto();
  202. url += "&wrkey=" +
  203. encodeURIComponent(this.urlCrypto_.getManager().getWrappedKey());
  204. }
  205. G_Debug(this, "getRequestURL returning: " + url);
  206. return url;
  207. }
  208. PROT_ListManager.prototype.checkForUpdates = function() {
  209. this.currentUpdateChecker_ = null;
  210. if (this.rpcPending_) {
  211. G_Debug(this, 'checkForUpdates: old callback is still pending...');
  212. return false;
  213. }
  214. G_Debug(this, 'checkForUpdates: scheduling request..');
  215. this.rpcPending_ = true;
  216. this.xmlFetcher_ = new PROT_XMLFetcher();
  217. this.xmlFetcher_.get(this.getRequestURL_(this.updateserverURL_),
  218. BindToObject(this.rpcDone, this));
  219. return true;
  220. }
  221. PROT_ListManager.prototype.rpcDone = function(data) {
  222. G_Debug(this, "Called rpcDone");
  223. this.rpcPending_ = false;
  224. this.xmlFetcher_ = null;
  225. if (!data || !data.length) {
  226. G_Debug(this, "No data. Returning");
  227. return;
  228. }
  229. data = this.checkMac_(data);
  230. if (data.length == 0) {
  231. return;
  232. }
  233. var dbUpdateSrv = Cc["@google.com/dbupdateservice;1"]
  234. .getService(Ci.GTBIDbUpdateService);
  235. try {
  236. dbUpdateSrv.updateTables(data);
  237. } catch (e) {
  238. G_Debug(this, "Skipping update, write thread busy.");
  239. return;
  240. }
  241. var tableNames = this.setTableVersions_(data);
  242. G_Debug(this, "Updated tables: " + tableNames);
  243. for (var t = 0, name = null; name = tableNames[t]; ++t) {
  244. if (!this.tablesData_[name])
  245. this.tablesData_[name] = new PROT_TRTable(name);
  246. if (this.registrar_.isKnownEventType(name)) {
  247. this.registrar_.fire(name, { table: this.tablesData_[name] });
  248. }
  249. }
  250. }
  251. PROT_ListManager.prototype.checkMac_ = function(data) {
  252. var dataTables = data.split('\n\n');
  253. var returnString = "";
  254. for (var t = 0; t < dataTables.length; ++t) {
  255. var table = dataTables[t];
  256. var firstLineEnd = table.indexOf("\n");
  257. while (firstLineEnd == 0) {
  258. table = table.substring(1);
  259. firstLineEnd = table.indexOf("\n");
  260. }
  261. if (firstLineEnd == -1) {
  262. G_Debug(this, "expecting at least 2 lines");
  263. continue;
  264. }
  265. var versionLine = table.substring(0, firstLineEnd);
  266. var versionParser = new PROT_VersionParser("dummy");
  267. if (!versionParser.fromString(versionLine)) {
  268. G_Debug(this, "Failed to parse version string");
  269. continue;
  270. }
  271. if (versionParser.mac && versionParser.macval.length > 0) {
  272. var updateData = table.substring(firstLineEnd + 1) + '\n';
  273. if (!this.urlCrypto_)
  274. this.urlCrypto_ = new PROT_UrlCrypto();
  275. var computedMac = this.urlCrypto_.computeMac(updateData);
  276. if (computedMac != versionParser.macval) {
  277. G_Debug(this, "mac doesn't match: " + computedMac + " != " +
  278. versionParser.macval)
  279. continue;
  280. }
  281. } else {
  282. if (this.tablesKnown_[versionParser.type] &&
  283. this.tablesKnown_[versionParser.type].requireMac) {
  284. G_Debug(this, "mac required but none provided");
  285. continue;
  286. }
  287. }
  288. returnString += table + "\n\n";
  289. }
  290. return returnString;
  291. }
  292. function TEST_PROT_ListManager() {
  293. if (G_GDEBUG) {
  294. var z = "listmanager UNITTEST";
  295. G_debugService.enableZone(z);
  296. G_Debug(z, "Starting");
  297. var listManager = new PROT_ListManager(true /*testing*/);
  298. var data = "a bad update string";
  299. G_Assert(z, "" == listManager.checkMac_(data),
  300. "checkMac returned bogus string");
  301. data = "[test-foo-domain 1.12]\n+http://foo.com\n\n";
  302. G_Assert(z, data == listManager.checkMac_("\n\n" + data),
  303. "failed to parse extra new lines");
  304. data = "[test-foo-domain 1.12]\n+http://foo.com\n\n";
  305. G_Assert(z, data == listManager.checkMac_("\n\n" + data),
  306. "extra newlines");
  307. data = "[test-foo-domain 1.12]\n+http://foo.com" +
  308. "\n\n" +
  309. "[test-bar-domain 1.23]\n+http://bar.com\n\n";
  310. G_Assert(z, data == listManager.checkMac_(data),
  311. "failed to parse 1 blank line between tables");
  312. var dataExtra = "[test-foo-domain 1.12]\n+http://foo.com" +
  313. "\n\n\n" +
  314. "[test-bar-domain 1.23]\n+http://bar.com\n\n";
  315. G_Assert(z, data == listManager.checkMac_(dataExtra),
  316. "failed to parse 2 blank line between tables");
  317. var dataExtra = "[test-foo-domain 1.12]\n+http://foo.com" +
  318. "\n\n\n\n" +
  319. "[test-bar-domain 1.23]\n+http://bar.com\n\n";
  320. G_Assert(z, data == listManager.checkMac_(dataExtra),
  321. "failed to parse 3 blank line between tables");
  322. data = "[test4-badheader-url 1.asfd dfui]\n+http://www.google.com/\n";
  323. G_Assert(z, "" == listManager.checkMac_(data),
  324. "invalid header allowed");
  325. data = "[test4-bad-name-url 1.asfd dfui]\n+http://www.google.com/\n";
  326. G_Assert(z, "" == listManager.checkMac_(data),
  327. "invalid header allowed");
  328. data = "";
  329. var set1Name = "test1-foo-domain";
  330. data += "[" + set1Name + " 1.2]\n";
  331. var set1 = {};
  332. for (var i = 0; i < 10; i++) {
  333. set1["http://" + i + ".com"] = 1;
  334. data += "+" + i + ".com\t1\n";
  335. }
  336. data += "\n";
  337. var set2Name = "test2-foo-domain";
  338. data += "\n[" + set2Name + " 1.7]\n";
  339. var set2 = {};
  340. for (var i = 0; i < 5; i++) {
  341. set2["http://" + i + ".com"] = 1;
  342. data += "+" + i + ".com\t1\n";
  343. }
  344. data += "\n";
  345. var set3Name = "test-white-domain";
  346. var set3data = "";
  347. var set3 = {};
  348. for (var i = 1; i <= 3; i++) {
  349. set3["http://white" + i + ".com"] = 1;
  350. set3data += "+white" + i + ".com\t1\n";
  351. }
  352. if (!listManager.urlCrypto_)
  353. listManager.urlCrypto_ = new PROT_UrlCrypto();
  354. var macval = listManager.urlCrypto_.computeMac(set3data);
  355. data += "\n[" + set3Name + " 1.1][mac=" + macval + "]\n";
  356. data += set3data;
  357. var newval = "012" + macval.substr(3);
  358. var set4Name = "test-mac-domain";
  359. data += "\n";
  360. data += "\n[" + set4Name + " 1.1][mac=" + newval + "]\n";
  361. data += set3data;
  362. data += "\n" +
  363. "[test4-badheader-url 1.asfd dfui]\n" + // Malformed header
  364. "+foo1\tbar\n" +
  365. "+foo2\tbar\n" +
  366. "+foo3\tbar\n" +
  367. "+foo4\tbar\n";
  368. "\n" +
  369. "[test4-bad-name-url 1.asfd dfui]\n" + // Malformed header
  370. "+foo1\tbar\n" +
  371. "+foo2\tbar\n" +
  372. "+foo3\tbar\n" +
  373. "+foo4\tbar\n";
  374. function checkTables() {
  375. var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
  376. var vp;
  377. for (var prop in set1) {
  378. G_Assert(z,
  379. listManager.tablesData_[set1Name].find(prop) == 1,
  380. "Couldn't find member " + prop + " of set1");
  381. listManager.tablesData_[set1Name].erase(prop);
  382. vp = listManager.tablesKnown_[set1Name];
  383. }
  384. G_Assert(z, "2" == vp.minor, "set1 table version mismatch");
  385. G_Assert(z, "1.2" == listManager.prefs_.getPref(prefBase + vp.type),
  386. "set1 table version mismatch (pref)");
  387. for (var prop in set2) {
  388. G_Assert(z,
  389. listManager.tablesData_[set2Name].find(prop) == 1,
  390. "Couldn't find member " + prop + " of set2");
  391. listManager.tablesData_[set2Name].erase(prop);
  392. }
  393. vp = listManager.tablesKnown_[set2Name];
  394. G_Assert(z, "7" == vp.minor, "set2 table version mismatch");
  395. G_Assert(z, "1.7" == listManager.prefs_.getPref(prefBase + vp.type),
  396. "set2 table version mismatch (pref)");
  397. for (var prop in set3) {
  398. G_Assert(z,
  399. listManager.tablesData_[set3Name].find(prop) == 1,
  400. "Couldn't find member " + prop + " of set3 from disk.");
  401. listManager.tablesData_[set3Name].erase(prop);
  402. }
  403. vp = listManager.tablesKnown_[set3Name];
  404. G_Assert(z, "1" == vp.minor, "set3 table version mismatch " + vp.minor);
  405. G_Assert(z, "1.1" == listManager.prefs_.getPref(prefBase + vp.type),
  406. "set3 table version mismatch (pref)");
  407. G_Assert(z,
  408. !listManager.tablesData_[set4Name],
  409. "Set 4 shouldn't exist!  It had the wrong mac.");
  410. G_Debug(z, "PASSED");
  411. z = "dbupdateservice UNITTEST";
  412. G_Debug(z, "Starting");
  413. var data =
  414. "[test1-black-url 1.1]\n" +
  415. "+foo1\tbar\n" +
  416. "+foo2\n" +           // Malformed
  417. "+foo3\tbar\n" +
  418. "+foo4\tbar\n" +
  419. "\n" +
  420. "[test2-black-url 1.2]\n" +
  421. "+foo1\tbar\n" +
  422. "+foo2\tbar\n" +
  423. "+foo3\tbar\n" +
  424. "+foo4\tbar\n" +
  425. "\n" +
  426. "[test3-black-url 1.3]\n" +
  427. "+foo1\tbar\n" +
  428. "+foo2\tbar\n" +
  429. "+foo3\tbar\n" +
  430. "+foo4\n" +          // Malformed
  431. "\n" +
  432. "[test4-black-url 1.4]\n" +
  433. "+foo1\tbar\n" +
  434. "+foo2\tbar\n" +
  435. "+foo3\tbar\n" +
  436. "+foo4\tbar\n" +
  437. "\n";
  438. var dbUpdateSrv = Cc["@google.com/dbupdateservice;1"]
  439. .getService(Ci.GTBIDbUpdateService);
  440. dbUpdateSrv.updateTables(data);
  441. function dbupdateCheckTables2() {
  442. G_Debug(z, "Starting checks after callback 2");
  443. var table = new PROT_TRTable("test4-black-url");
  444. G_Assert(z, table.dbTable_.exists("foo2") == "bar", "missing key foo2");
  445. G_Assert(z, table.dbTable_.exists("foo4") == "bar", "missing key foo4");
  446. G_Assert(z, table.dbTable_.exists("foo5") == "bar", "missing key foo5");
  447. G_Assert(z, !table.dbTable_.exists("foo1"), "foo1 not removed");
  448. G_Assert(z, !table.dbTable_.exists("foo3"), "foo2 not removed");
  449. table.dbTable_.remove("foo2");
  450. table.dbTable_.remove("foo4");
  451. table.dbTable_.remove("foo5");
  452. G_Debug(z, "PASSED");
  453. }
  454. function dbupdateCheckTables1() {
  455. G_Debug(z, "Starting checks after callback 1");
  456. var table = new PROT_TRTable("test1-black-url");
  457. var i;
  458. G_Assert(z, !table.dbTable_.exists("foo2"),
  459. "test1: found malformed key/value pair");
  460. for (i = 1; i <= 4; ++i)
  461. table.erase("foo" + i);
  462. table = new PROT_TRTable("test2-black-url");
  463. for (i = 1; i <= 4; ++i) {
  464. G_Assert(z, table.dbTable_.exists("foo" + i) == "bar",
  465. "test2: missing key foo" + i);
  466. table.erase("foo" + i);
  467. }
  468. table = new PROT_TRTable("test3-black-url");
  469. G_Assert(z, !table.dbTable_.exists("foo4"),
  470. "test3: found malformed key/value pair");
  471. for (i = 1; i <= 4; ++i)
  472. table.erase("foo" + i);
  473. table = new PROT_TRTable("test4-black-url");
  474. for (i = 1; i <= 4; ++i) {
  475. G_Assert(z, table.dbTable_.exists("foo" + i) == "bar",
  476. "test4: missing key foo" + i);
  477. }
  478. G_Debug(z, "First set of tests passed, moving on to second set");
  479. var data =
  480. "[test4-black-url 1.5]\n" +
  481. "-foo1\n" +
  482. "+foo5\tbar\n" +
  483. "-foo3\n" +
  484. "\n";
  485. dbUpdateSrv.updateTables(data);
  486. new G_Alarm(dbupdateCheckTables2, 800);
  487. }
  488. new G_Alarm(dbupdateCheckTables1, 800);
  489. }
  490. }
  491. }
  492.