home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Minami 80
/
MINAMI80.iso
/
Extra
/
DivXInstaller.exe
/
$PLUGINSDIR
/
GoogleToolbarFirefox.msi
/
xpi
/
amulet-jslib
/
listmanager.js
< prev
next >
Wrap
Text File
|
2006-05-15
|
15KB
|
492 lines
function PROT_ListManager(opt_testing) {
this.debugZone = "listmanager";
if (opt_testing)
this.debugZone += "testing";
G_debugService.enableZone(this.debugZone);
this.testing_ = !!opt_testing;
this.currentUpdateChecker_ = null; // set when we toggle updates
this.rpcPending_ = false;
var self = this;
this.updateserverURL_ = PROT_globalStore.getUpdateserverURL();
this.tablesKnown_ = {};
if (this.testing_) {
this.tablesKnown_ = {
"test1-foo-domain": new PROT_VersionParser("test1-foo-domain", 0, -1),
"test2-foo-domain": new PROT_VersionParser("test2-foo-domain", 0, -1),
"test-white-domain": new PROT_VersionParser("test-white-domain", 0, -1,
true /* require mac*/),
"test-mac-domain": new PROT_VersionParser("test-mac-domain", 0, -1,
true /* require mac */)
};
}
this.tablesData_ = {};
this.registrar_ = new EventRegistrar({});
this.urlCrypto_ = null;
this.prefs_ = new G_Preferences();
}
PROT_ListManager.prototype.registerTable = function(tableName,
opt_requireMac,
opt_callback) {
var table = new PROT_VersionParser(tableName, 1, -1, opt_requireMac);
this.tablesKnown_[tableName] = table;
this.tablesData_[tableName] = new PROT_TRTable(tableName);
if (opt_callback) {
if (!this.registrar_.isKnownEventType(tableName))
this.registrar_.addEventType(tableName);
this.registrar_.registerListener(tableName, opt_callback);
G_Debug(this, "registering callback for " + tableName);
}
return true;
}
PROT_ListManager.prototype.enableUpdateTables = function(tables) {
var changed = false;
for (var i = 0; i < tables.length; ++i) {
var table = this.tablesKnown_[tables[i]];
if (table) {
G_Debug(this, "Enabling table updates for " + tables[i]);
table.needsUpdate = true;
changed = true;
}
}
if (changed === true)
this.maybeToggleUpdateChecking();
}
PROT_ListManager.prototype.disableUpdateTables = function(tables) {
var changed = false;
for (var i = 0; i < tables.length; ++i) {
var table = this.tablesKnown_[tables[i]];
if (table) {
G_Debug(this, "Disabling table updates for " + tables[i]);
table.needsUpdate = false;
changed = true;
}
}
if (changed === true)
this.maybeToggleUpdateChecking();
}
PROT_ListManager.prototype.requireTableUpdates = function() {
for (var type in this.tablesKnown_) {
if (this.tablesKnown_[type].major == 0)
continue;
if (this.tablesKnown_[type].needsUpdate)
return true;
}
return false;
}
PROT_ListManager.prototype.maybeStartManagingUpdates = function() {
if (this.testing_)
return;
this.maybeToggleUpdateChecking();
}
PROT_ListManager.prototype.maybeToggleUpdateChecking = function() {
if (this.testing_)
return;
if (this.requireTableUpdates() === true) {
G_Debug(this, "Starting managing lists");
this.loadTableVersions_();
if (!this.currentUpdateChecker_)
this.currentUpdateChecker_ =
new G_Alarm(BindToObject(this.checkForUpdates, this), 3000);
this.startUpdateChecker();
} else {
G_Debug(this, "Stopping managing lists (if currently active)");
this.stopUpdateChecker(); // Cancel pending updates
}
}
PROT_ListManager.prototype.startUpdateChecker = function() {
this.stopUpdateChecker();
var thirtyMinutes = 30 * 60 * 1000;
this.updateChecker_ = new G_Alarm(BindToObject(this.checkForUpdates, this),
thirtyMinutes, true /* repeat */);
}
PROT_ListManager.prototype.stopUpdateChecker = function() {
if (this.updateChecker_) {
this.updateChecker_.cancel();
this.updateChecker_ = null;
}
}
PROT_ListManager.prototype.safeLookup = function(table, key) {
var result = false;
try {
var map = this.tablesData_[table];
result = map.find(key);
} catch(e) {
result = false;
G_Debug(this, "Safelookup masked failure for " + table + ", key " + key + ": " + e);
}
return result;
}
PROT_ListManager.prototype.safeInsert = function(table, key, value) {
if (!this.tablesKnown_[table]) {
G_Debug(this, "Unknown table: " + table);
return false;
}
if (!this.tablesData_[table])
this.tablesData_[table] = new PROT_TRTable(table);
try {
this.tablesData_[table].insert(key, value);
} catch (e) {
G_Debug(this, "Cannot insert key " + key + " value " + value);
G_Debug(this, e);
return false;
}
return true;
}
PROT_ListManager.prototype.safeErase = function(table, key) {
if (!this.tablesKnown_[table]) {
G_Debug(this, "Unknown table: " + table);
return false;
}
if (!this.tablesData_[table])
return false;
return this.tablesData_[table].erase(key);
}
PROT_ListManager.prototype.loadTableVersions_ = function() {
var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
for (var table in this.tablesKnown_) {
var version = this.prefs_.getPref(prefBase + table, "1.-1");
G_Debug(this, "loadTableVersion " + table + ": " + version);
var tokens = version.split(".");
G_Assert(this, tokens.length == 2, "invalid version number");
this.tablesKnown_[table].major = tokens[0];
this.tablesKnown_[table].minor = tokens[1];
}
}
PROT_ListManager.prototype.setTableVersions_ = function(updateString) {
var updatedTables = [];
var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
var startPos = updateString.indexOf('[');
var endPos;
while (startPos != -1) {
if (0 == startPos || ('\n' == updateString[startPos - 1] &&
'\n' == updateString[startPos - 2])) {
endPos = updateString.indexOf('\n', startPos);
if (endPos != -1) {
var line = updateString.substring(startPos, endPos);
var versionParser = new PROT_VersionParser("dummy");
if (versionParser.fromString(line)) {
var tableName = versionParser.type;
var version = versionParser.major + '.' + versionParser.minor;
G_Debug(this, "Set table version for " + tableName + ": " + version);
this.prefs_.setPref(prefBase + tableName, version);
this.tablesKnown_[tableName].ImportVersion(versionParser);
updatedTables.push(tableName);
}
}
}
startPos = updateString.indexOf('[', startPos + 1);
}
return updatedTables;
}
PROT_ListManager.prototype.getRequestURL_ = function(url) {
url += "version=";
var firstElement = true;
var requestMac = false;
for (var type in this.tablesKnown_) {
if (this.tablesKnown_[type].major == 0)
continue;
if (this.tablesKnown_[type].needsUpdate == false)
continue;
if (!firstElement) {
url += ","
} else {
firstElement = false;
}
url += type + ":" + this.tablesKnown_[type].toUrl();
if (this.tablesKnown_[type].requireMac)
requestMac = true;
}
if (requestMac) {
if (!this.urlCrypto_)
this.urlCrypto_ = new PROT_UrlCrypto();
url += "&wrkey=" +
encodeURIComponent(this.urlCrypto_.getManager().getWrappedKey());
}
G_Debug(this, "getRequestURL returning: " + url);
return url;
}
PROT_ListManager.prototype.checkForUpdates = function() {
this.currentUpdateChecker_ = null;
if (this.rpcPending_) {
G_Debug(this, 'checkForUpdates: old callback is still pending...');
return false;
}
G_Debug(this, 'checkForUpdates: scheduling request..');
this.rpcPending_ = true;
this.xmlFetcher_ = new PROT_XMLFetcher();
this.xmlFetcher_.get(this.getRequestURL_(this.updateserverURL_),
BindToObject(this.rpcDone, this));
return true;
}
PROT_ListManager.prototype.rpcDone = function(data) {
G_Debug(this, "Called rpcDone");
this.rpcPending_ = false;
this.xmlFetcher_ = null;
if (!data || !data.length) {
G_Debug(this, "No data. Returning");
return;
}
data = this.checkMac_(data);
if (data.length == 0) {
return;
}
var dbUpdateSrv = Cc["@google.com/dbupdateservice;1"]
.getService(Ci.GTBIDbUpdateService);
try {
dbUpdateSrv.updateTables(data);
} catch (e) {
G_Debug(this, "Skipping update, write thread busy.");
return;
}
var tableNames = this.setTableVersions_(data);
G_Debug(this, "Updated tables: " + tableNames);
for (var t = 0, name = null; name = tableNames[t]; ++t) {
if (!this.tablesData_[name])
this.tablesData_[name] = new PROT_TRTable(name);
if (this.registrar_.isKnownEventType(name)) {
this.registrar_.fire(name, { table: this.tablesData_[name] });
}
}
}
PROT_ListManager.prototype.checkMac_ = function(data) {
var dataTables = data.split('\n\n');
var returnString = "";
for (var t = 0; t < dataTables.length; ++t) {
var table = dataTables[t];
var firstLineEnd = table.indexOf("\n");
while (firstLineEnd == 0) {
table = table.substring(1);
firstLineEnd = table.indexOf("\n");
}
if (firstLineEnd == -1) {
G_Debug(this, "expecting at least 2 lines");
continue;
}
var versionLine = table.substring(0, firstLineEnd);
var versionParser = new PROT_VersionParser("dummy");
if (!versionParser.fromString(versionLine)) {
G_Debug(this, "Failed to parse version string");
continue;
}
if (versionParser.mac && versionParser.macval.length > 0) {
var updateData = table.substring(firstLineEnd + 1) + '\n';
if (!this.urlCrypto_)
this.urlCrypto_ = new PROT_UrlCrypto();
var computedMac = this.urlCrypto_.computeMac(updateData);
if (computedMac != versionParser.macval) {
G_Debug(this, "mac doesn't match: " + computedMac + " != " +
versionParser.macval)
continue;
}
} else {
if (this.tablesKnown_[versionParser.type] &&
this.tablesKnown_[versionParser.type].requireMac) {
G_Debug(this, "mac required but none provided");
continue;
}
}
returnString += table + "\n\n";
}
return returnString;
}
function TEST_PROT_ListManager() {
if (G_GDEBUG) {
var z = "listmanager UNITTEST";
G_debugService.enableZone(z);
G_Debug(z, "Starting");
var listManager = new PROT_ListManager(true /*testing*/);
var data = "a bad update string";
G_Assert(z, "" == listManager.checkMac_(data),
"checkMac returned bogus string");
data = "[test-foo-domain 1.12]\n+http://foo.com\n\n";
G_Assert(z, data == listManager.checkMac_("\n\n" + data),
"failed to parse extra new lines");
data = "[test-foo-domain 1.12]\n+http://foo.com\n\n";
G_Assert(z, data == listManager.checkMac_("\n\n" + data),
"extra newlines");
data = "[test-foo-domain 1.12]\n+http://foo.com" +
"\n\n" +
"[test-bar-domain 1.23]\n+http://bar.com\n\n";
G_Assert(z, data == listManager.checkMac_(data),
"failed to parse 1 blank line between tables");
var dataExtra = "[test-foo-domain 1.12]\n+http://foo.com" +
"\n\n\n" +
"[test-bar-domain 1.23]\n+http://bar.com\n\n";
G_Assert(z, data == listManager.checkMac_(dataExtra),
"failed to parse 2 blank line between tables");
var dataExtra = "[test-foo-domain 1.12]\n+http://foo.com" +
"\n\n\n\n" +
"[test-bar-domain 1.23]\n+http://bar.com\n\n";
G_Assert(z, data == listManager.checkMac_(dataExtra),
"failed to parse 3 blank line between tables");
data = "[test4-badheader-url 1.asfd dfui]\n+http://www.google.com/\n";
G_Assert(z, "" == listManager.checkMac_(data),
"invalid header allowed");
data = "[test4-bad-name-url 1.asfd dfui]\n+http://www.google.com/\n";
G_Assert(z, "" == listManager.checkMac_(data),
"invalid header allowed");
data = "";
var set1Name = "test1-foo-domain";
data += "[" + set1Name + " 1.2]\n";
var set1 = {};
for (var i = 0; i < 10; i++) {
set1["http://" + i + ".com"] = 1;
data += "+" + i + ".com\t1\n";
}
data += "\n";
var set2Name = "test2-foo-domain";
data += "\n[" + set2Name + " 1.7]\n";
var set2 = {};
for (var i = 0; i < 5; i++) {
set2["http://" + i + ".com"] = 1;
data += "+" + i + ".com\t1\n";
}
data += "\n";
var set3Name = "test-white-domain";
var set3data = "";
var set3 = {};
for (var i = 1; i <= 3; i++) {
set3["http://white" + i + ".com"] = 1;
set3data += "+white" + i + ".com\t1\n";
}
if (!listManager.urlCrypto_)
listManager.urlCrypto_ = new PROT_UrlCrypto();
var macval = listManager.urlCrypto_.computeMac(set3data);
data += "\n[" + set3Name + " 1.1][mac=" + macval + "]\n";
data += set3data;
var newval = "012" + macval.substr(3);
var set4Name = "test-mac-domain";
data += "\n";
data += "\n[" + set4Name + " 1.1][mac=" + newval + "]\n";
data += set3data;
data += "\n" +
"[test4-badheader-url 1.asfd dfui]\n" + // Malformed header
"+foo1\tbar\n" +
"+foo2\tbar\n" +
"+foo3\tbar\n" +
"+foo4\tbar\n";
"\n" +
"[test4-bad-name-url 1.asfd dfui]\n" + // Malformed header
"+foo1\tbar\n" +
"+foo2\tbar\n" +
"+foo3\tbar\n" +
"+foo4\tbar\n";
function checkTables() {
var prefBase = PROT_globalStore.getTableVersionPrefPrefix();
var vp;
for (var prop in set1) {
G_Assert(z,
listManager.tablesData_[set1Name].find(prop) == 1,
"Couldn't find member " + prop + " of set1");
listManager.tablesData_[set1Name].erase(prop);
vp = listManager.tablesKnown_[set1Name];
}
G_Assert(z, "2" == vp.minor, "set1 table version mismatch");
G_Assert(z, "1.2" == listManager.prefs_.getPref(prefBase + vp.type),
"set1 table version mismatch (pref)");
for (var prop in set2) {
G_Assert(z,
listManager.tablesData_[set2Name].find(prop) == 1,
"Couldn't find member " + prop + " of set2");
listManager.tablesData_[set2Name].erase(prop);
}
vp = listManager.tablesKnown_[set2Name];
G_Assert(z, "7" == vp.minor, "set2 table version mismatch");
G_Assert(z, "1.7" == listManager.prefs_.getPref(prefBase + vp.type),
"set2 table version mismatch (pref)");
for (var prop in set3) {
G_Assert(z,
listManager.tablesData_[set3Name].find(prop) == 1,
"Couldn't find member " + prop + " of set3 from disk.");
listManager.tablesData_[set3Name].erase(prop);
}
vp = listManager.tablesKnown_[set3Name];
G_Assert(z, "1" == vp.minor, "set3 table version mismatch " + vp.minor);
G_Assert(z, "1.1" == listManager.prefs_.getPref(prefBase + vp.type),
"set3 table version mismatch (pref)");
G_Assert(z,
!listManager.tablesData_[set4Name],
"Set 4 shouldn't exist! It had the wrong mac.");
G_Debug(z, "PASSED");
z = "dbupdateservice UNITTEST";
G_Debug(z, "Starting");
var data =
"[test1-black-url 1.1]\n" +
"+foo1\tbar\n" +
"+foo2\n" + // Malformed
"+foo3\tbar\n" +
"+foo4\tbar\n" +
"\n" +
"[test2-black-url 1.2]\n" +
"+foo1\tbar\n" +
"+foo2\tbar\n" +
"+foo3\tbar\n" +
"+foo4\tbar\n" +
"\n" +
"[test3-black-url 1.3]\n" +
"+foo1\tbar\n" +
"+foo2\tbar\n" +
"+foo3\tbar\n" +
"+foo4\n" + // Malformed
"\n" +
"[test4-black-url 1.4]\n" +
"+foo1\tbar\n" +
"+foo2\tbar\n" +
"+foo3\tbar\n" +
"+foo4\tbar\n" +
"\n";
var dbUpdateSrv = Cc["@google.com/dbupdateservice;1"]
.getService(Ci.GTBIDbUpdateService);
dbUpdateSrv.updateTables(data);
function dbupdateCheckTables2() {
G_Debug(z, "Starting checks after callback 2");
var table = new PROT_TRTable("test4-black-url");
G_Assert(z, table.dbTable_.exists("foo2") == "bar", "missing key foo2");
G_Assert(z, table.dbTable_.exists("foo4") == "bar", "missing key foo4");
G_Assert(z, table.dbTable_.exists("foo5") == "bar", "missing key foo5");
G_Assert(z, !table.dbTable_.exists("foo1"), "foo1 not removed");
G_Assert(z, !table.dbTable_.exists("foo3"), "foo2 not removed");
table.dbTable_.remove("foo2");
table.dbTable_.remove("foo4");
table.dbTable_.remove("foo5");
G_Debug(z, "PASSED");
}
function dbupdateCheckTables1() {
G_Debug(z, "Starting checks after callback 1");
var table = new PROT_TRTable("test1-black-url");
var i;
G_Assert(z, !table.dbTable_.exists("foo2"),
"test1: found malformed key/value pair");
for (i = 1; i <= 4; ++i)
table.erase("foo" + i);
table = new PROT_TRTable("test2-black-url");
for (i = 1; i <= 4; ++i) {
G_Assert(z, table.dbTable_.exists("foo" + i) == "bar",
"test2: missing key foo" + i);
table.erase("foo" + i);
}
table = new PROT_TRTable("test3-black-url");
G_Assert(z, !table.dbTable_.exists("foo4"),
"test3: found malformed key/value pair");
for (i = 1; i <= 4; ++i)
table.erase("foo" + i);
table = new PROT_TRTable("test4-black-url");
for (i = 1; i <= 4; ++i) {
G_Assert(z, table.dbTable_.exists("foo" + i) == "bar",
"test4: missing key foo" + i);
}
G_Debug(z, "First set of tests passed, moving on to second set");
var data =
"[test4-black-url 1.5]\n" +
"-foo1\n" +
"+foo5\tbar\n" +
"-foo3\n" +
"\n";
dbUpdateSrv.updateTables(data);
new G_Alarm(dbupdateCheckTables2, 800);
}
new G_Alarm(dbupdateCheckTables1, 800);
}
}
}