diff --git a/mozilla/browser/base/content/browser-doctype.inc b/mozilla/browser/base/content/browser-doctype.inc index bd29b3aa160..05daaf8a80a 100644 --- a/mozilla/browser/base/content/browser-doctype.inc +++ b/mozilla/browser/base/content/browser-doctype.inc @@ -15,5 +15,9 @@ %placesDTD; #endif +#ifdef MOZ_SAFE_BROWSING + +%safebrowsingDTD; +#endif ]> diff --git a/mozilla/browser/base/content/browser-sets.inc b/mozilla/browser/base/content/browser-sets.inc index cada7eb1fd3..bb4fc9a58c4 100644 --- a/mozilla/browser/base/content/browser-sets.inc +++ b/mozilla/browser/base/content/browser-sets.inc @@ -178,6 +178,9 @@ oncommand="PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_HISTORY);"/> +#endif +#ifdef MOZ_SAFE_BROWSING +#include ../../components/safebrowsing/content/commands.inc #endif diff --git a/mozilla/browser/base/content/browser.xul b/mozilla/browser/base/content/browser.xul index f4caff49b88..de09333ddf2 100644 --- a/mozilla/browser/base/content/browser.xul +++ b/mozilla/browser/base/content/browser.xul @@ -52,6 +52,10 @@ #endif +#ifdef MOZ_SAFE_BROWSING + +#endif + @@ -63,6 +67,9 @@ +#ifdef MOZ_SAFE_BROWSING + +#endif @@ -486,6 +499,11 @@ /> + +#ifdef MOZ_SAFE_BROWSING +#include ../../components/safebrowsing/content/safebrowsing.inc +#endif + #include ../../../toolkit/components/typeaheadfind/content/findBar.inc diff --git a/mozilla/browser/base/content/global-scripts.inc b/mozilla/browser/base/content/global-scripts.inc index 2ee2e8b604e..30e74765698 100644 --- a/mozilla/browser/base/content/global-scripts.inc +++ b/mozilla/browser/base/content/global-scripts.inc @@ -52,3 +52,6 @@ + diff --git a/mozilla/browser/locales/jar.mn b/mozilla/browser/locales/jar.mn index e1236a985f5..b205708bcb8 100644 --- a/mozilla/browser/locales/jar.mn +++ b/mozilla/browser/locales/jar.mn @@ -38,6 +38,9 @@ * locale/browser/bookmarks/bookmarks.properties (%chrome/browser/bookmarks/bookmarks.properties) * locale/browser/bookmarks/bookmarksProperties.dtd (%chrome/browser/bookmarks/bookmarksProperties.dtd) #endif +#ifdef MOZ_SAFE_BROWSING + locale/browser/safebrowsing/phishing-afterload-warning-message.dtd (%chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd) +#endif #ifdef MOZ_FEEDS locale/browser/feeds/subscribe.dtd (%chrome/browser/feeds/subscribe.dtd) locale/browser/feeds/options.dtd (%chrome/browser/feeds/options.dtd) diff --git a/mozilla/browser/themes/pinstripe/browser/jar.mn b/mozilla/browser/themes/pinstripe/browser/jar.mn index 242a30e8be4..dcbe3cc994d 100644 --- a/mozilla/browser/themes/pinstripe/browser/jar.mn +++ b/mozilla/browser/themes/pinstripe/browser/jar.mn @@ -64,6 +64,14 @@ classic.jar: skin/classic/browser/bookmarks/livemark-item.png (bookmarks/livemark-item.png) skin/classic/browser/bookmarks/folderarrow-hover.png (bookmarks/folderarrow-hover.png) skin/classic/browser/bookmarks/folderarrow.png (bookmarks/folderarrow.png) +#endif +#ifdef MOZ_SAFE_BROWSING + skin/classic/browser/safebrowsing/browser-protection.css (safebrowsing/browser-protection.css) + skin/classic/browser/safebrowsing/close16x16.png (safebrowsing/close16x16.png) + skin/classic/browser/safebrowsing/dim.png (safebrowsing/dim.png) + skin/classic/browser/safebrowsing/tail.png (safebrowsing/tail.png) + skin/classic/browser/safebrowsing/warning16x16.png (safebrowsing/warning16x16.png) + skin/classic/browser/safebrowsing/warning24x24.png (safebrowsing/warning24x24.png) #endif skin/classic/browser/preferences/Options.png (preferences/Options.png) skin/classic/browser/preferences/preferences.css (preferences/preferences.css) diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/browser-protection.css b/mozilla/browser/themes/pinstripe/browser/safebrowsing/browser-protection.css new file mode 100644 index 00000000000..a42102fbafd --- /dev/null +++ b/mozilla/browser/themes/pinstripe/browser/safebrowsing/browser-protection.css @@ -0,0 +1,130 @@ +#safebrowsing-palm-message { + display: none; + position: fixed; + top: 0px; + left: 0px; + z-index: 2; +} + +.safebrowsing-palm-message-bubble { + background-color: white; + -moz-box-sizing: border-box; + -moz-border-radius: 10px; + margin-top: -5px; + padding: 10px; + border-top: 1px solid; + border-left: 1px solid; + border-right: 2px solid; + border-bottom: 2px solid; + z-index: 1; +} + +.safebrowsing-palm-fixed-width { + width: 400px; + max-width: 400px; +} + +.safebrowsing-palm-title { + font-size: 20px; + font-weight: bold; +} + +#safebrowsing-palm-title-icon { + height: 24px; + width: 24px; + max-height: 24px; +} + +.safebrowsing-palm-link { + color: blue; + cursor: pointer; + text-decoration: underline +} + +.safebrowsing-palm-paragraph { + padding-bottom: 2em; +} + +#safebrowsing-palm-close { + cursor: pointer; + max-width: 16px !important; + height: 16px; + width: 16px; +} + +#safebrowsing-palm-message-tail-container { + display: none; + position: fixed; + top: 0px; + left: 0px; + border-right: 2px solid; + z-index: 3; + height: 67px; + margin: 0; + padding: 0; +} + +#safebrowsing-palm-message-tail { + height: 67px; + width: 24px; + max-width: 24px; + z-index: 3; +} + +#safebrowsing-palm-message-titlebox { + padding-bottom: 5px; + padding-left: 10px; +} + +#safebrowsing-palm-message-title { + padding-left: 5px; +} + +#safebrowsing-palm-message-actionbox { + padding-top: 10px; + padding-bottom: 15px; +} + +.safebrowsing-palm-bigtext { + font-size: 14px; + font-weight: bold; +} + +.safebrowsing-palm-smalltext { + font-size: 10px; +} + +#safebrowsing-palm-google-logo { + height: 32px; + max-height: 32px; + width: 78px; +} + +#safebrowsing-dim-area-canvas { + background-image: url("chrome://browser/skin/safebrowsing/dim.png"); + height: 0px; +} + +#safebrowsing-dim-area-transp { + background-image: url("chrome://browser/skin/safebrowsing/dim.png"); + height: 0px; + left: 0px; + top: 0px; + position: fixed; + display: none; +} + +#safebrowsing-pref-caption { + background-color: #2222EE; +} + +#safebrowsing-pref-caption text { + text-align: center; + color: #FFFFFF; + font-size: 150%; + font-family: arial, helvetica, sans-serif; +} + +#safebrowsing-urlbar-icon { + padding-right: 2px; +} diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/close16x16.png b/mozilla/browser/themes/pinstripe/browser/safebrowsing/close16x16.png new file mode 100644 index 00000000000..abf7f386f8b Binary files /dev/null and b/mozilla/browser/themes/pinstripe/browser/safebrowsing/close16x16.png differ diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/dim.png b/mozilla/browser/themes/pinstripe/browser/safebrowsing/dim.png new file mode 100644 index 00000000000..9e458d0563f Binary files /dev/null and b/mozilla/browser/themes/pinstripe/browser/safebrowsing/dim.png differ diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/tail.png b/mozilla/browser/themes/pinstripe/browser/safebrowsing/tail.png new file mode 100644 index 00000000000..a973739885f Binary files /dev/null and b/mozilla/browser/themes/pinstripe/browser/safebrowsing/tail.png differ diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning16x16.png b/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning16x16.png new file mode 100644 index 00000000000..53f65e09fee Binary files /dev/null and b/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning16x16.png differ diff --git a/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning24x24.png b/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning24x24.png new file mode 100644 index 00000000000..274fc131b65 Binary files /dev/null and b/mozilla/browser/themes/pinstripe/browser/safebrowsing/warning24x24.png differ diff --git a/mozilla/browser/themes/winstripe/browser/jar.mn b/mozilla/browser/themes/winstripe/browser/jar.mn index d98ffc87c12..baa247b308f 100644 --- a/mozilla/browser/themes/winstripe/browser/jar.mn +++ b/mozilla/browser/themes/winstripe/browser/jar.mn @@ -40,6 +40,14 @@ classic.jar: skin/classic/browser/bookmarks/addBookmark.css (bookmarks/addBookmark.css) skin/classic/browser/bookmarks/bookmarksManager.css (bookmarks/bookmarksManager.css) skin/classic/browser/bookmarks/Bookmarks-toolbar.png (bookmarks/Bookmarks-toolbar.png) +#endif +#ifdef MOZ_SAFE_BROWSING + skin/classic/browser/safebrowsing/browser-protection.css (safebrowsing/browser-protection.css) + skin/classic/browser/safebrowsing/close16x16.png (safebrowsing/close16x16.png) + skin/classic/browser/safebrowsing/dim.png (safebrowsing/dim.png) + skin/classic/browser/safebrowsing/tail.png (safebrowsing/tail.png) + skin/classic/browser/safebrowsing/warning16x16.png (safebrowsing/warning16x16.png) + skin/classic/browser/safebrowsing/warning24x24.png (safebrowsing/warning24x24.png) #endif skin/classic/browser/preferences/Options.png (preferences/Options.png) skin/classic/browser/preferences/preferences.css (preferences/preferences.css) diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/browser-protection.css b/mozilla/browser/themes/winstripe/browser/safebrowsing/browser-protection.css new file mode 100644 index 00000000000..a42102fbafd --- /dev/null +++ b/mozilla/browser/themes/winstripe/browser/safebrowsing/browser-protection.css @@ -0,0 +1,130 @@ +#safebrowsing-palm-message { + display: none; + position: fixed; + top: 0px; + left: 0px; + z-index: 2; +} + +.safebrowsing-palm-message-bubble { + background-color: white; + -moz-box-sizing: border-box; + -moz-border-radius: 10px; + margin-top: -5px; + padding: 10px; + border-top: 1px solid; + border-left: 1px solid; + border-right: 2px solid; + border-bottom: 2px solid; + z-index: 1; +} + +.safebrowsing-palm-fixed-width { + width: 400px; + max-width: 400px; +} + +.safebrowsing-palm-title { + font-size: 20px; + font-weight: bold; +} + +#safebrowsing-palm-title-icon { + height: 24px; + width: 24px; + max-height: 24px; +} + +.safebrowsing-palm-link { + color: blue; + cursor: pointer; + text-decoration: underline +} + +.safebrowsing-palm-paragraph { + padding-bottom: 2em; +} + +#safebrowsing-palm-close { + cursor: pointer; + max-width: 16px !important; + height: 16px; + width: 16px; +} + +#safebrowsing-palm-message-tail-container { + display: none; + position: fixed; + top: 0px; + left: 0px; + border-right: 2px solid; + z-index: 3; + height: 67px; + margin: 0; + padding: 0; +} + +#safebrowsing-palm-message-tail { + height: 67px; + width: 24px; + max-width: 24px; + z-index: 3; +} + +#safebrowsing-palm-message-titlebox { + padding-bottom: 5px; + padding-left: 10px; +} + +#safebrowsing-palm-message-title { + padding-left: 5px; +} + +#safebrowsing-palm-message-actionbox { + padding-top: 10px; + padding-bottom: 15px; +} + +.safebrowsing-palm-bigtext { + font-size: 14px; + font-weight: bold; +} + +.safebrowsing-palm-smalltext { + font-size: 10px; +} + +#safebrowsing-palm-google-logo { + height: 32px; + max-height: 32px; + width: 78px; +} + +#safebrowsing-dim-area-canvas { + background-image: url("chrome://browser/skin/safebrowsing/dim.png"); + height: 0px; +} + +#safebrowsing-dim-area-transp { + background-image: url("chrome://browser/skin/safebrowsing/dim.png"); + height: 0px; + left: 0px; + top: 0px; + position: fixed; + display: none; +} + +#safebrowsing-pref-caption { + background-color: #2222EE; +} + +#safebrowsing-pref-caption text { + text-align: center; + color: #FFFFFF; + font-size: 150%; + font-family: arial, helvetica, sans-serif; +} + +#safebrowsing-urlbar-icon { + padding-right: 2px; +} diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/close16x16.png b/mozilla/browser/themes/winstripe/browser/safebrowsing/close16x16.png new file mode 100644 index 00000000000..abf7f386f8b Binary files /dev/null and b/mozilla/browser/themes/winstripe/browser/safebrowsing/close16x16.png differ diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/dim.png b/mozilla/browser/themes/winstripe/browser/safebrowsing/dim.png new file mode 100644 index 00000000000..9e458d0563f Binary files /dev/null and b/mozilla/browser/themes/winstripe/browser/safebrowsing/dim.png differ diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/tail.png b/mozilla/browser/themes/winstripe/browser/safebrowsing/tail.png new file mode 100644 index 00000000000..a973739885f Binary files /dev/null and b/mozilla/browser/themes/winstripe/browser/safebrowsing/tail.png differ diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/warning16x16.png b/mozilla/browser/themes/winstripe/browser/safebrowsing/warning16x16.png new file mode 100644 index 00000000000..53f65e09fee Binary files /dev/null and b/mozilla/browser/themes/winstripe/browser/safebrowsing/warning16x16.png differ diff --git a/mozilla/browser/themes/winstripe/browser/safebrowsing/warning24x24.png b/mozilla/browser/themes/winstripe/browser/safebrowsing/warning24x24.png new file mode 100644 index 00000000000..274fc131b65 Binary files /dev/null and b/mozilla/browser/themes/winstripe/browser/safebrowsing/warning24x24.png differ diff --git a/mozilla/toolkit/components/Makefile.in b/mozilla/toolkit/components/Makefile.in index 483046ea86d..746c44ed4f2 100644 --- a/mozilla/toolkit/components/Makefile.in +++ b/mozilla/toolkit/components/Makefile.in @@ -77,6 +77,10 @@ ifdef MOZ_XPINSTALL DIRS += downloads endif +ifdef MOZ_URL_CLASSIFIER +DIRS += url-classifier +endif + DIRS += \ commandlines \ startup \ @@ -87,8 +91,4 @@ EXTRA_PP_COMPONENTS = nsDefaultCLH.js endif # MOZ_XUL_APP -ifdef MOZ_URL_CLASSIFIER -DIRS += url-classifier -endif - include $(topsrcdir)/config/rules.mk diff --git a/mozilla/toolkit/components/url-classifier/content/application.js b/mozilla/toolkit/components/url-classifier/content/application.js index 95775604f14..e3a09f4a7d2 100644 --- a/mozilla/toolkit/components/url-classifier/content/application.js +++ b/mozilla/toolkit/components/url-classifier/content/application.js @@ -34,6 +34,8 @@ * * ***** END LICENSE BLOCK ***** */ +// TODO: We don't use this class very much. Try to use native nsIFile instead +// and remove this file. /** * A simple helper class that enables us to get or create the @@ -42,7 +44,6 @@ function PROT_ApplicationDirectory() { this.debugZone = "appdir"; this.appDir_ = G_File.getProfileFile(); - this.appDir_.append(PROT_GlobalStore.getAppDirectoryName()); G_Debug(this, "Application directory is " + this.appDir_.path); } diff --git a/mozilla/toolkit/components/url-classifier/content/listmanager.js b/mozilla/toolkit/components/url-classifier/content/listmanager.js index 3bd063acfd1..4368b706f4a 100644 --- a/mozilla/toolkit/components/url-classifier/content/listmanager.js +++ b/mozilla/toolkit/components/url-classifier/content/listmanager.js @@ -67,11 +67,23 @@ // of the list comprise its name, so the listmanager should easily // be able to figure out what to do with what list (i.e., no // need for step 4). -// TODO reading, writing, and whatnot code should be cleaned up -// TODO read/write asynchronously // TODO more comprehensive update tests, for example add unittest check // that the listmanagers tables are properly written on updates +/** + * The base pref name for where we keep table version numbers. + * We add append the table name to this and set the value to + * the version. E.g., tableversion.goog-black-enchash may have + * a value of 1.1234. + */ +const kTableVersionPrefPrefix = "urlclassifier.tableversion."; + +/** + * Pref name for the update server. + * TODO: Add support for multiple providers. + */ +const kUpdateServerUrl = "urlclassifier.provider.0.updateURL"; + /** * A ListManager keeps track of black and white lists and knows @@ -83,46 +95,23 @@ function PROT_ListManager() { this.debugZone = "listmanager"; G_debugService.enableZone(this.debugZone); - // We run long-lived operations on "threads" (user-level - // time-slices) in order to prevent locking up the UI - var threadConfig = { - "interleave": true, - "runtime": 80, - "delay": 400, - }; - this.threadQueue_ = new TH_ThreadQueue(threadConfig); - this.appDir_ = null; - this.initAppDir_(); // appDir can be changed with setAppDir this.currentUpdateChecker_ = null; // set when we toggle updates this.rpcPending_ = false; - this.readingData_ = false; + this.prefs_ = new G_Preferences(); - // We don't want to start checking against our lists until we've - // read them. But then again, we don't want to queue URLs to check - // forever. So if we haven't successfully read our lists after a - // certain amount of time, just pretend. - this.dataImportedAtLeastOnce_ = false; - var self = this; - new G_Alarm(function() { self.dataImportedAtLeastOnce_ = true; }, 60 * 1000); - - // TOOD(tc): PREF - this.updateserverURL_ = PROT_GlobalStore.getUpdateserverURL(); + this.updateserverURL_ = this.prefs_.getPref(kUpdateServerUrl, null); // The lists we know about and the parses we can use to read // them. Default all to the earlies possible version (1.-1); this // version will get updated when successfully read from disk or // fetch updates. this.tablesKnown_ = {}; + this.isTesting_ = false; - if (PROT_GlobalStore.isTesting()) { + if (this.isTesting_) { // populate with some tables for unittesting this.tablesKnown_ = { - // "goog-white-domain": new PROT_VersionParser("goog-white-domain", 1, -1), - // "goog-black-url" : new PROT_VersionParser("goog-black-url", 1, -1), - // "goog-black-enchash": new PROT_VersionParser("goog-black-enchash", 1, -1), - // "goog-white-url": new PROT_VersionParser("goog-white-url", 1, -1), - // - // A major version of zero means local, so don't ask for updates + // A major version of zero means local, so don't ask for updates "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" : @@ -137,6 +126,7 @@ function PROT_ListManager() { this.tablesData = {}; + // Lazily create urlCrypto (see tr-fetcher.js) this.urlCrypto_ = null; } @@ -152,6 +142,7 @@ PROT_ListManager.prototype.registerTable = function(tableName, if (!table) return false; this.tablesKnown_[tableName] = table; + this.tablesData[tableName] = newUrlClassifierTable(tableName); return true; } @@ -214,7 +205,7 @@ PROT_ListManager.prototype.requireTableUpdates = function() { * (where we store the lists) might not be available. */ PROT_ListManager.prototype.maybeStartManagingUpdates = function() { - if (PROT_GlobalStore.isTesting()) + if (this.isTesting_) return; // We might have been told about tables already, so see if we should be @@ -229,16 +220,14 @@ PROT_ListManager.prototype.maybeStartManagingUpdates = function() { PROT_ListManager.prototype.maybeToggleUpdateChecking = function() { // If we are testing or dont have an application directory yet, we should // not start reading tables from disk or schedule remote updates - if (PROT_GlobalStore.isTesting() || !this.appDir_) + if (this.isTesting_) return; // We update tables if we have some tables that want updates. If there // are no tables that want to be updated - we dont need to check anything. if (this.requireTableUpdates() === true) { G_Debug(this, "Starting managing lists"); - // Read new table data if necessary - if we already have data we just - // skip reading from disk - new G_Alarm(BindToObject(this.readDataFiles, this), 0); + this.loadTableVersions_(); // Multiple warden can ask us to reenable updates at the same time, but we // really just need to schedule a single update. if (!this.currentUpdateChecker_) @@ -274,45 +263,6 @@ PROT_ListManager.prototype.stopUpdateChecker = function() { } } -/** - * - */ -PROT_ListManager.prototype.initAppDir_ = function() { - var dir = G_File.getProfileFile(); - dir.append(PROT_GlobalStore.getAppDirectoryName()); - if (!dir.exists()) { - try { - dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); - } catch (e) { - G_Error(this, dir.path + " couldn't be created."); - } - } - this.setAppDir(dir); -} - -/** - * Set the directory in which we should serialize data - * - * @param appDir An nsIFile pointing to our directory (should exist) - */ -PROT_ListManager.prototype.setAppDir = function(appDir) { - G_Debug(this, "setAppDir: " + appDir.path); - this.appDir_ = appDir; -} - -/** - * Clears the specified table - * @param table Name of the table that we want to consult - * @returns true if the table exists, false otherwise - */ -PROT_ListManager.prototype.clearList = function(table) { - if (!this.tablesKnown_[table]) - return false; - - this.tablesData[table] = newUrlClassifierTable(this.tablesKnown_[table].type); - return true; -} - /** * Provides an exception free way to look up the data in a table. We * use this because at certain points our tables might not be loaded, @@ -379,112 +329,62 @@ PROT_ListManager.prototype.safeRemove = function(table, key) { return this.tablesData[table].remove(key); } -PROT_ListManager.prototype.getTable = function(tableName) { - return this.tablesData[tableName]; +/** + * We store table versions in user prefs. This method pulls the values out of + * the user prefs and into the tablesKnown objects. + */ +PROT_ListManager.prototype.loadTableVersions_ = function() { + // Pull values out of prefs. + var prefBase = kTableVersionPrefPrefix; + 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]; + } } /** - * Returns a list of files that we should try to read. We do not return - * tables that already have data or that we tried to read in the past. - * @returns array of file names + * Get lines of the form "[goog-black-enchash 1.1234]" or + * "[goog-white-url 1.1234 update]" and set the version numbers in the user + * pref. + * @param updateString String containing the response from the server. + * @return Array a list of table names */ +PROT_ListManager.prototype.setTableVersions_ = function(updateString) { + var updatedTables = []; -PROT_ListManager.prototype.listUnreadDataFiles = function() { - // Now we need to read all of our nice data files. - var files = []; - for (var type in this.tablesKnown_) { - var table = this.tablesKnown_[type]; - // Do not read data for tables that we already know about - if (this.tablesData[type] || table.didRead === true) - continue; + var prefBase = kTableVersionPrefPrefix; + var startPos = updateString.indexOf('['); + var endPos; + while (startPos != -1) { + // [ needs to be the start of a new line + 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"); - // Tables that dont require updates are not read from disk either - if (table.needsUpdate === false) - continue; + 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); - var filename = type + ".sst"; - var file = this.appDir_.clone(); - file.append(filename); - if (file.exists() && file.isFile() && file.isReadable()) { - G_Debug(this, "Found saved data for: " + type); - files.push(file); - } else { - G_Debug(this, "Failed to find saved data for: " + type); + updatedTables.push(tableName); + } + } } + // This could catch option params, but that's ok. The double newline + // check will skip over it. + startPos = updateString.indexOf('[', startPos + 1); } - - return files; -} - -/** - * Reads all data files from storage - * @returns true if we started reading data from disk, false otherwise. - */ -PROT_ListManager.prototype.readDataFiles = function() { - if (this.readingData_ === true) { - G_Debug(this, "Already reading data from disk"); - return true; - } - - if (this.rpcPending_ === true) { - G_Debug(this, "Cannot read data files while an update RPC is pending"); - new G_Alarm(BindToObject(this.readDataFiles, this), 10 * 1000); - return false; - } - - // If we have no files there is nothing more for us todo - var files = this.listUnreadDataFiles(); - if (!files.length) - return true; - - this.readingData_ = true; - - // Remember that we attempted to read from all tables - for (var type in this.tablesKnown_) - this.tablesKnown_[type].didRead = true; - - // TODO: Should probably break this up on a thread - var data = ""; - for (var i = 0; i < files.length; ++i) { - G_Debug(this, "Trying to read: " + files[i].path); - var gFile = new G_FileReader(files[i]); - data += gFile.read() + "\n"; - gFile.close(); - } - - this.deserialize_(data, BindToObject(this.dataFromDisk, this)); - return true; -} - -/** - * Creates a WireFormatReader and calls deserialize on it. - */ -PROT_ListManager.prototype.deserialize_ = function(data, callback) { - var wfr = new PROT_WireFormatReader(this.threadQueue_, this.tablesData); - wfr.deserialize(data, callback); -} - -/** - * A callback that is executed when we have read our table data from - * disk. - * - * @param tablesKnown An array that maps table name to current version - * @param tablesData An array that maps a table name to a Map which - * contains key value pairs. - */ -PROT_ListManager.prototype.dataFromDisk = function(tablesKnown, tablesData) { - G_Debug(this, "Called dataFromDisk"); - - this.importData_(tablesKnown, tablesData); - - this.readingData_ = false; - - // If we have more files to read schedule another round of reading - var files = this.listUnreadDataFiles(); - if (files.length) - new G_Alarm(BindToObject(this.readDataFiles, this), 0); - - return true; + return updatedTables; } /** @@ -500,7 +400,7 @@ PROT_ListManager.prototype.getRequestURL_ = function(url) { var firstElement = true; var requestMac = false; - for(var type in this.tablesKnown_) { + for (var type in this.tablesKnown_) { // All tables with a major of 0 are internal tables that we never // update remotely. if (this.tablesKnown_[type].major == 0) @@ -551,14 +451,10 @@ PROT_ListManager.prototype.checkForUpdates = function() { return false; } - if (this.readingData_) { - G_Debug(this, 'checkForUpdate: still reading data from disk...'); - - // Reschedule the update to happen in a little while - new G_Alarm(BindToObject(this.checkForUpdates, this), 500); + if (!this.updateserverURL_) { + G_Debug(this, 'checkForUpdates: no update server url'); return false; } - G_Debug(this, 'checkForUpdates: scheduling request..'); this.rpcPending_ = true; this.xmlFetcher_ = new PROT_XMLFetcher(); @@ -574,170 +470,110 @@ PROT_ListManager.prototype.checkForUpdates = function() { */ PROT_ListManager.prototype.rpcDone = function(data) { G_Debug(this, "Called rpcDone"); - /* Runs in a thread and executes the callback when ready */ - this.deserialize_(data, BindToObject(this.dataReady, this)); - + this.rpcPending_ = false; this.xmlFetcher_ = null; + + if (!data || !data.length) { + G_Debug(this, "No data. Returning"); + return; + } + + // Only use the the data if the mac matches. + data = this.checkMac_(data); + + if (data.length == 0) { + return; + } + + // List updates (local lists) don't work yet. See bug 336203. + throw Exception("dbservice not yet implemented."); + + var dbUpdateSrv = Cc["@mozilla.org/url-classifier/dbservice;1"] + .getService(Ci.nsIUrlClassifierDBService); + + // Update the tables on disk. + try { + dbUpdateSrv.updateTables(data); + } catch (e) { + // dbUpdateSrv will throw an error if the background thread is already + // working. In this case, we just wait for the next scheduled update. + G_Debug(this, "Skipping update, write thread busy."); + return; + } + + // While the update is being processed by a background thread, we need + // to also update the table versions. + var tableNames = this.setTableVersions_(data); + G_Debug(this, "Updated tables: " + tableNames); + + for (var t = 0, name = null; name = tableNames[t]; ++t) { + // Create the table object if it doesn't exist. + if (!this.tablesData[name]) + this.tablesData[name] = newUrlClassifierTable(name); + } } /** - * @returns Boolean indicating if it has read data from somewhere (e.g., - * disk) - */ -PROT_ListManager.prototype.hasData = function() { - return !!this.dataImportedAtLeastOnce_; -} - -/** - * Check if the mac passed, if required. + * Given the server response, extract out the new table lines and table + * version numbers. If the table has a mac, also check to see if it matches + * the data. * - * @param oldParser The current version parser for the table - * @param newParser A version parser returned by the WireFormatReader - * - * @returns true if no mac is required, or if it is and the newParser says it - * didn't fail, false otherwise + * @param data String update string from the server + * @return String The same update string sans tables with invalid macs. */ -PROT_ListManager.prototype.maybeCheckMac = function(oldParser, newParser) { - if (!oldParser.requireMac) - return true; +PROT_ListManager.prototype.checkMac_ = function(data) { + var dataTables = data.split('\n\n'); + var returnString = ""; - if (newParser.mac && !newParser.macFailed) - return true; + for (var table = null, t = 0; table = dataTables[t]; ++t) { + var firstLineEnd = table.indexOf("\n"); + while (firstLineEnd == 0) { + // Skip leading blank lines + table = table.substring(1); + firstLineEnd = table.indexOf("\n"); + } + if (firstLineEnd == -1) { + continue; + } - G_Debug(this, "mac required and it failed"); - return false; -} + var versionLine = table.substring(0, firstLineEnd); + var versionParser = new PROT_VersionParser("dummy"); + if (!versionParser.fromString(versionLine)) { + // Failed to parse the version string, skip this table. + G_Debug(this, "Failed to parse version string"); + continue; + } -/** - * We've deserialized tables from disk or the update server, now let's - * swap them into the tables we're currently using. - * - * @param tablesKnown An array that maps table name to current version - * @param tablesData An array that maps a table name to a Map which - * contains key value pairs. - * @returns Array of strings holding the names of tables we updated - */ -PROT_ListManager.prototype.importData_ = function(tablesKnown, tablesData) { - this.dataImportedAtLeastOnce_ = true; + if (versionParser.mac && versionParser.macval.length > 0) { + // Includes a mac, so we check it. + var updateData = table.substring(firstLineEnd + 1) + '\n'; + if (!this.urlCrypto_) + this.urlCrypto_ = new PROT_UrlCrypto(); - var changes = []; - - // If our data has changed, update it - if (tablesKnown && tablesData) { - // Update our tables with the new data - for (var name in tablesKnown) { - // WireFormatReader constructs VersionParsers from scratch and doesn't - // know about the requireMac flag, so check it now - if (tablesKnown[name] && this.tablesKnown_[name] && - this.tablesKnown_[name] != tablesKnown[name] && - this.maybeCheckMac(this.tablesKnown_[name], tablesKnown[name])) { - changes.push(name); - - this.tablesKnown_[name].ImportVersion(tablesKnown[name]); - this.tablesData[name] = tablesData[name]; + var computedMac = this.urlCrypto_.computeMac(updateData); + if (computedMac != versionParser.macval) { + G_Debug(this, "mac doesn't match: " + computedMac + " != " + + versionParser.macval) + continue; + } + } else { + // No mac in the return. Check to see if it's required. If it is + // required, skip this data. + if (this.tablesKnown_[versionParser.type] && + this.tablesKnown_[versionParser.type].requireMac) { + continue; } } + + // Everything looks ok, add it to the return string. + returnString += table + "\n\n"; } - return changes; -} - -/** - * A callback that is executed when we have updated the tables from - * the server. We are provided with the new table versions and the - * corresponding data. - * - * @param tablesKnown An array that maps table name to current version - * @param tablesData An array that maps a table name to a Map which - * contains key value pairs. - */ -PROT_ListManager.prototype.dataReady = function(tablesKnown, tablesData) { - G_Debug(this, "Called dataReady"); - - // First, replace the current tables we're using - var changes = this.importData_(tablesKnown, tablesData); - - // Then serialize the new tables to disk - if (changes.length) { - G_Debug(this, "Committing " + changes.length + " changed tables to disk."); - for (var i = 0; i < changes.length; i++) { - this.storeTable(changes[i], - this.tablesData[changes[i]], - this.tablesKnown_[changes[i]]); - } - } - - this.rpcPending_ = false; // todo maybe can do away cuz asynch - G_Debug(this, "Done writing data to disk."); -} - -/** - * Serialize a table to disk. - * - * @param tableName String holding the name of the table to serialize - * - * @param opt_table Reference to the Map holding the table (if omitted, - * we look the table up) - * - * @param opt_parser Reference to the versionparser for this table (if - * omitted we look the table up) - */ -PROT_ListManager.prototype.storeTable = function(tableName, - opt_table, - opt_parser) { - - var table = opt_table ? opt_table : this.tablesData[tableName]; - var parser = opt_parser ? opt_parser : this.tablesKnown_[tableName]; - - if (!table || ! parser) - G_Error(this, "Tried to serialize a non-existent table: " + tableName); - - var wfw = new PROT_WireFormatWriter(this.threadQueue_); - wfw.serialize(table, parser, BindToObject(this.writeDataFile, - this, - tableName)); -} - -/** - * Takes a serialized table and writes it into our application directory. - * - * @param tableName String containing the name of the table, used to - * create the filename - * - * @param tableData Serialized version of the table - */ -PROT_ListManager.prototype.writeDataFile = function(tableName, tableData) { - var filename = tableName + ".sst"; - - G_Debug(this, "Serializing to " + filename); - - try { - var tmpFile = G_File.createUniqueTempFile(filename); - var tmpFileWriter = new G_FileWriter(tmpFile); - - tmpFileWriter.write(tableData); - tmpFileWriter.close(); - - } catch(e) { - G_Debug(this, e); - G_Error(this, "Couldn't write to temp file: " + filename); - } - - // Now overwrite! - try { - tmpFile.moveTo(this.appDir_, filename); - } catch(e) { - G_Debug(this, e); - G_Error(this, "Couldn't overwrite existing table: " + - tmpFile.path + ', ' + - this.appDir_.path + ', ' + filename); - tmpFile.remove(false /* not recursive */); - } - G_Debug(this, "Serializing to " + filename + " finished."); + return returnString; } PROT_ListManager.prototype.QueryInterface = function(iid) { - if (iid.equals(Components.interfaces.nsISample) || + if (iid.equals(Components.interfaces.nsISupports) || iid.equals(Components.interfaces.nsIUrlListManager)) return this; @@ -750,7 +586,7 @@ PROT_ListManager.prototype.QueryInterface = function(iid) { // provider_name-semantic_type-table_type. For example, goog-white-enchash // or goog-black-url. function newUrlClassifierTable(name) { - G_Debug("protfactory", "Trying to create a new nsIUrlClassifierTable: " + name); + G_Debug("protfactory", "Creating a new nsIUrlClassifierTable: " + name); var tokens = name.split('-'); var type = tokens[2]; var table = Cc['@mozilla.org/url-classifier/table;1?type=' + type] diff --git a/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js b/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js index 459d4b41b01..9f9f7361a30 100644 --- a/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js +++ b/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js @@ -64,6 +64,12 @@ // the client to re-key. The client will issue a new HTTPS getkey request // at this time if it has only issued one before +// We store the user key in this file. The key can be used to verify signed +// server updates. +const kKeyFilename = "kf.txt"; + +// If we don't have a key, we can get one at this url. +const kGetKeyUrl = "safebrowsing.provider.0.keyURL"; /** * A key manager for UrlCrypto. There should be exactly one of these @@ -94,8 +100,7 @@ function PROT_UrlCryptoKeyManager(opt_keyFilename, opt_testing) { this.rekeyTries_ = 0; this.keyFilename_ = opt_keyFilename ? - opt_keyFilename : - PROT_GlobalStore.getKeyFilename(); + opt_keyFilename : kKeyFilename; // Convenience properties this.MAX_REKEY_TRIES = PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES; @@ -154,8 +159,9 @@ PROT_UrlCryptoKeyManager.prototype.reKey = function() { this.rekeyTries_++; G_Debug(this, "Attempting to re-key"); - var url = PROT_GlobalStore.getGetKeyURL(); - if (!this.testing_) + var prefs = new G_Preferences(); + var url = prefs.getPref(kGetKeyUrl, null); + if (!this.testing_ && url) (new PROT_XMLFetcher()).get(url, BindToObject(this.onGetKeyResponse, this)); } diff --git a/mozilla/toolkit/components/url-classifier/content/wireformat.js b/mozilla/toolkit/components/url-classifier/content/wireformat.js index fcf90cec55d..2d064495a22 100644 --- a/mozilla/toolkit/components/url-classifier/content/wireformat.js +++ b/mozilla/toolkit/components/url-classifier/content/wireformat.js @@ -84,6 +84,7 @@ function PROT_VersionParser(type, opt_major, opt_minor, opt_requireMac) { this.requireMac = !!opt_requireMac; this.update = false; + this.needsUpdate = false; // used by ListManager to determine update policy // Used by ListerManager to see if we have read data for this table from // disk. Once we read a table from disk, we are not going to do so again // but instead update remotely if necessary. @@ -115,8 +116,6 @@ PROT_VersionParser.prototype.ImportVersion = function(version) { */ PROT_VersionParser.prototype.toString = function() { var s = "[" + this.type + " " + this.major + "." + this.minor + "]"; - if (this.mac) - s += "[mac=" + this.macval + "]"; return s; } @@ -157,10 +156,9 @@ PROT_VersionParser.prototype.processOldFormat_ = function(line) { return true; } -/** - * Takes a string like [name-of-table 1.1] and figures out the type - * and corresponding version numbers. - * +/** + * Takes a string like [name-of-table 1.1 [update]][mac=MAC] and figures out the + * type and corresponding version numbers. * @returns true if the string could be parsed, false otherwise */ PROT_VersionParser.prototype.fromString = function(line) { @@ -212,7 +210,7 @@ PROT_VersionParser.prototype.processOptTokens_ = function(line) { this.mac = true; if (tokenparts.length < 2) { G_Debug(this, "Found mac flag but not mac value!"); - return false; + return false; } // The mac value may have "=" in it, so we can't just use tokenparts[1]. // Instead, just take the rest of tokens[i] after the first "=" @@ -227,550 +225,27 @@ PROT_VersionParser.prototype.processOptTokens_ = function(line) { return true; } - -/** - * A WireFormatWriter can serialize table data - * - * @param threadQueue A thread queue we should run on - * - * @constructor - */ -function PROT_WireFormatWriter(threadQueue) { - this.threadQueue_ = threadQueue; - this.debugZone = "wireformatwriter"; -} - -/** - * Serializes a table to a string. - * - * @param tableData Reference to the table data we should serialize - * - * @param vParser Reference to the version parser/unparser we should use - * - * @param callback Reference to a function we should call when complete. - * The callback will be invoked with a string holding - * the serialized data as an argument - * - * @returns False if the serializer is busy, else true - * - */ -PROT_WireFormatWriter.prototype.serialize = function(tableData, - vParser, - callback) { - if (this.callback_) { - G_Debug(this, "Serializer busy"); - return false; - } - - this.callback_ = callback; - this.current_ = 0; - this.serialized_ = vParser.toString() + "\n"; - var cnt = {}; - this.keyList_ = tableData.getKeys(cnt); - this.tableData_ = tableData; - - this.threadQueue_.addWorker(BindToObject(this.doWorkUnit, this), - BindToObject(this.isComplete, this)); - this.threadQueue_.run(); - - return true; -} - -/** - * Serialize a chunk of data. This is periodically invoked by the - * threadqueue. - */ -PROT_WireFormatWriter.prototype.doWorkUnit = function() { - for (var i = 0; i < 10 && this.current_ < this.keyList_.length; i++) { - var key = this.keyList_[this.current_]; - if (key) { - var value = this.tableData_.findValue(key); - this.serialized_ += "+" + key + "\t" + value + "\n"; - } - this.current_++; - } - - if (this.isComplete()) - this.onComplete(); -} - -/** - * Are we done serializing? Called by the threadqueue to tell when - * to stop running this thread. - * - * @returns Boolean indicating if we're done serializing - */ -PROT_WireFormatWriter.prototype.isComplete = function() { - return this.current_ >= this.keyList_.length; -} - -/** - * When we're done, call the callback - */ -PROT_WireFormatWriter.prototype.onComplete = function() { - this.callback_(this.serialized_); - this.callback_ = null; -} - -/** - * A WireFormatReader can deserialize data. - * - * @constructor - * - * @param threadQueue A global thread queue that we use to schedule our - * work so that we do not take up too much time at one. - * - * @param opt_existingTablesData Optional reference to a map of tables - * into which we should merge the data being deserialized - */ -function PROT_WireFormatReader(threadQueue, opt_existingTablesData) { - this.debugZone = "wireformatreader"; - this.existingTablesData_ = opt_existingTablesData; - this.threadQueue_ = threadQueue; - this.callback_ = null; - - // For mac'ing updates - this.urlCrypto_ = null; - var keyUrl = null; - try { - keyUrl = PROT_GlobalStore.getGetKeyURL(); - } catch (e) { - G_Debug(this, "No key url, disabling mac'ed updates"); - } - if (keyUrl) { - this.urlCrypto_ = new PROT_UrlCrypto(); - } -} - -/** - * Starts a thread to process the input data. - * - * @param tableUpdate A string that contains the data for updating the - * tables that we know about. - * - * @param callback A user specificed callback that is being executed - * when data processing completes. The callback is provided - * with two arguments: tablesKnown and tablesData - * - * @returns true is new data is being process, or false on failure. - */ -PROT_WireFormatReader.prototype.deserialize = function(tableUpdate, callback) { - this.tableUpdate_ = tableUpdate; - this.tablesKnown_ = {}; // version parsers - this.tablesData_ = {}; // TRTables - - if (this.callback_ != null) { - G_Debug(this, "previous deserialize is still running"); - return false; - } - - this.callback_ = callback; - this.offset_ = 0; - this.resetTableState_(); - - // On empty data, we just invoke the callback directly - if (!this.tableUpdate_ || !this.tableUpdate_.length) { - G_Debug(this, "No data. Calling back."); - this.onComplete(); - return true; - } - - this.threadQueue_.addWorker(BindToObject(this.processLine_, this), - BindToObject(this.isComplete, this)); - this.threadQueue_.run(); - - return true; -} - -/** - * Resets the per table state - */ -PROT_WireFormatReader.prototype.resetTableState_ = function() { - this.vParser_ = null; - this.insert_ = 0; - this.remove_ = 0; -} - -/** - * Initalizes our state to process a new table. - * NOTE: For performance reasons, we might have drive the replacement of - * the table via a thread. - * - * @param line The input line that contains the table name and version - */ -PROT_WireFormatReader.prototype.processNewTable_ = function(line) { - this.vParser_ = new PROT_VersionParser("something"); - - // If there's an error, give up - if (!this.vParser_.fromString(line)) { - G_Debug(this, "Error in table header, skipping"); - this.vParser_ = null; - return; - } - - G_Debug(this, "processNewTable: " + this.vParser_.type + ": " + - this.vParser_.major + ":" + this.vParser_.minor + " update=" + - this.vParser_.update + " mac=" + this.vParser_.mac); - - // Create temporary table. PROT_TRTable() blows up if it doesn't like its - // name, so mask and just set vParser to null - try { - this.tablesData_[this.vParser_.type] = - newUrlClassifierTable(this.vParser_.type); - } catch(e) { - G_Debug(this, - "Unable to initialize new TRTable, because of exception: " + e); - this.vParser_ = null; - return; - } - if (this.vParser_.update && this.existingTablesData_ && - this.existingTablesData_[this.vParser_.type]) { - // If we update an existing table, we need to copy the old table - // data from the pre-existing tables - this.tablesData_[this.vParser_.type].replace( - this.existingTablesData_[this.vParser_.type]); - } - G_Debug(this, "processNewTable done"); -} - -/** - * Updates the contents of our temporary table. Exceptions should not - * be masked here -- they're caught at a higher level. - * - * @param line The input line that contains the new data - */ -PROT_WireFormatReader.prototype.processUpdateTable_ = function(line) { - // Regular update to the current version - var tokens = line.split("\t"); - var operation = tokens[0][0]; - var key = tokens[0].slice(1); - var value = tokens[1]; - - if (operation == "+") { - this.tablesData_[this.vParser_.type].insert(key, value); - this.insert_++; - } else { - this.tablesData_[this.vParser_.type].remove(key); - this.remove_++; - } -} - -/** - * Finish processing a table - */ -PROT_WireFormatReader.prototype.endTable_ = function() { - G_Debug(this, - "Finished: " + this.vParser_.type + " +" + - this.insert_ + " -" + this.remove_ + " mac'ing: " + this.vParser_.mac); - - if (this.vParser_.mac) { - var mac = this.urlCrypto_.finishMac(); - if (mac != this.vParser_.macval) { - G_Debug(this, "Mac didn't match! (" + mac + " != " - + this.vParser_.macval + ")"); - this.vParser_.macFailed = true; - } else { - G_Debug(this, "Computed mac matched sent mac: " + this.vParser_.macval); - } - } - - // Rollback if the mac failed. - if (this.vParser_.mac && this.vParser_.macFailed) { - this.tablesData_[this.vParser_.type] = undefined; - this.tablesKnown_[this.vParser_.type] = undefined; - G_Debug(this, "throwing away " + this.vParser_.type); - } else { - this.tablesKnown_[this.vParser_.type] = this.vParser_; - } - - this.resetTableState_(); -} - -/** - * Processes a chunk of data. TODO(MC): Make it so the mac is computed from a - * saved begin and end offset instead of computing line by line. - */ -PROT_WireFormatReader.prototype.processLine_ = function() { - //G_Debug(this, '> processline'); - for (var count = 0; - count < 5 && this.offset_ < this.tableUpdate_.length; count++) { - var newOffset = this.tableUpdate_.indexOf("\n", this.offset_); - var line = ""; - if (newOffset == -1) { - this.offset_ = this.tableUpdate_.length; - } else { - line = this.tableUpdate_.slice(this.offset_, newOffset); - this.offset_ = newOffset + 1; - } - - // Ignore empty lines if we currently do not have a table - if (!this.vParser_ && (!line || line[0] != '[')) { - continue; - } - - if (!line) { - // End of one table - pop the results - this.endTable_(); - } else if (line[0] == '[' && line.slice(-1) == ']') { - // processNewTable doesn't instantiate this.vParser_ in case of malformed - // headers, so the rest of the table lines will get skipped - this.processNewTable_(line); - - if (this.vParser_ && this.vParser_.mac) { - this.urlCrypto_.initMac(); - } - } else { - if (!this.vParser_) { - G_Debug(this, "Ignoring: " + line); - continue; - } - - // Now we try to read a data line. However the table could've - // been corrupted on disk (e.g., the browser suddenly quit while - // we were in the middle of writing a line). If so, - // porcessUpdateTable() will throw. In this case we want to - // resynch the whole table, so we skip this line and then - // explicitly set the table's minor version to -1 (the lowest - // possible -- not 0, which means the table is local), causing a - // full update the next time we ask for it. - // - // We ignore the case where we wrote an incomplete but malformed - // table -- it fixes itself over time as the missing keys become - // less relevant. - - try { - this.processUpdateTable_(line); - // Compute the mac over all the next lines until we finish the table - // TODO: This is ugly! line doesn't get the final '\n', so add it back. - // We could save the original line back up top, and use that instead, - // but that's yet more copying... - if (this.vParser_.mac) { - this.urlCrypto_.updateMacFromString(line + "\n"); - } - } catch(e) { - G_Debug(this, "MALFORMED TABLE LINE: [" + line + "]\n" + - "Skipping this line, and resetting table " + - this.vParser_.type + " to version -1.\n" + - "(This as a result of exception: " + e + ")"); - this.vParser_.minor = "-1"; - } - } - } - - // If the table we're reading is the last, then the for loop will - // fail, causing the table finish logic to be skipped. So here - // ensure that we finish up whatever table we're working on. - - if (this.vParser_ && this.offset_ >= this.tableUpdate_.length) { - G_Debug(this, - "Finished (final table): " + this.vParser_.type + " +" + - this.insert_ + " -" + this.remove_); - this.endTable_(); - } - - if (this.isComplete()) this.onComplete(); - //G_Debug(this, "< processline"); -} - -/** - * Returns true if all input data has been processed - */ -PROT_WireFormatReader.prototype.isComplete = function() { - return this.offset_ >= this.tableUpdate_.length; -} - -/** - * Notifies our caller of completion. - */ -PROT_WireFormatReader.prototype.onComplete = function() { - G_Debug(this, "Processing complete. Executing callback."); - this.callback_(this.tablesKnown_, this.tablesData_); - this.callback_ = null; -} - - function TEST_PROT_WireFormat() { if (G_GDEBUG) { - // Sorry, this is incredibly ugly. What we need is continuations -- each - // unittest that passes invokes the next. - - var z = "wireformat UNITTEST"; - G_debugService.enableZone(z); + var z = "versionparser UNITTEST"; G_Debug(z, "Starting"); - function testMalformedTables() { - G_Debug(z, "Testing malformed tables..."); - - var wfr = new PROT_WireFormatReader(new TH_ThreadQueue()); - - // Damn these unittests are ugly. Ugh. Now test handling corrupt tables - 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" + - "[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"; + var vp = new PROT_VersionParser("dummy"); + G_Assert(z, vp.fromString("[foo-bar-url 1.234]"), + "failed to parse old format"); + G_Assert(z, "foo-bar-url" == vp.type, "failed to parse type"); + G_Assert(z, "1" == vp.major, "failed to parse major"); + G_Assert(z, "234" == vp.minor, "failed to parse minor"); - function malformedcb(tablesKnown, tablesData) { - - // Table has malformed data - G_Assert(z, tablesKnown["test1-black-url"].minor == "-1", - "test table 1 didn't get reset"); - G_Assert(z, !!tablesData["test1-black-url"].exists("foo1"), - "test table 1 didn't set keys before the error"); - G_Assert(z, !!tablesData["test1-black-url"].exists("foo3"), - "test table 1 didn't set keys after the error"); + vp = new PROT_VersionParser("dummy"); + G_Assert(z, vp.fromString("[foo-bar-url 1.234][mac=567]"), + "failed to parse new format"); + G_Assert(z, "foo-bar-url" == vp.type, "failed to parse type"); + G_Assert(z, "1" == vp.major, "failed to parse major"); + G_Assert(z, "234" == vp.minor, "failed to parse minor"); + G_Assert(z, true == vp.mac, "failed to parse mac"); + G_Assert(z, "567" == vp.macval, "failed to parse macval"); - // Table should be good - G_Assert(z, tablesKnown["test2-black-url"].minor == "2", - "test table 1 didnt get correct version number"); - G_Assert(z, !!tablesData["test2-black-url"].exists("foo4"), - "test table 2 didnt parse properly"); - - // Table is malformed - G_Assert(z, tablesKnown["test3-black-url"].minor == "-1", - "test table 3 didn't get reset"); - G_Assert(z, !tablesData["test3-black-url"].exists("foo4"), - "test table 3 somehow has its malformed line?"); - - // Table should be good - G_Assert(z, tablesKnown["test4-black-url"].minor == "4", - "test table 4 didn't get correct version number"); - G_Assert(z, !!tablesData["test2-black-url"].exists("foo4"), - "test table 4 didnt parse properly"); - - // Table is malformed and should be unknown - G_Assert(z, !tablesKnown["test4-badheader-url"], - "test table header should't be known"); - - // Table is malformed and should be unknown - G_Assert(z, !tablesKnown["test4-bad-name-url"], - "test table header should't be known"); - - G_Debug(z, "PASSED"); - }; - - wfr.deserialize(data, malformedcb); - }; - - var testTablesData = {}; - - var tableName = "test-black-url"; - var data1 = "[" + tableName + " 1.5]\n"; - for (var i = 0; i < 100; i++) - data1 += "+http://exists" + i + "\t1\n"; - data1 += "-http://exists50\t1\n"; - data1 += "-http://exists666\t1\n"; - - var data2 = "[" + tableName + " 1.7 update]\n"; - for (var i = 0; i < 100; i++) - data2 += "-http://exists" + i + "\t1\n"; - - var set3Name = "test-white-domain"; - var set3data = ""; - // Use this string since it's the same in the update server unittest in - // /firefox/security/scripts/test/cheese/cheesey something.sh - for (var i = 1; i <= 3; i++) { - set3data += "+white" + i + ".com\t1\n"; - } - var urlCrypto = new PROT_UrlCrypto(); - var computedMac = urlCrypto.computeMac(set3data); - - function data1cb(tablesKnown, tablesData) { - G_Assert(z, - tablesData[tableName] != null, - "Didn't get our table back"); - - for (var i = 0; i < 100; i++) - if (i != 50) - G_Assert(z, - tablesData[tableName].exists("http://exists" + i) == "1", - "Item addition broken"); - - G_Assert(z, - !tablesData[tableName].exists("http://exists50"), - "Item removal broken"); - G_Assert(z, - !tablesData[tableName].exists("http://exists666"), - "Non-existent item"); - - G_Assert(z, tablesKnown[tableName].major == "1", "Major parsing broke"); - G_Assert(z, tablesKnown[tableName].minor == "5", "Major parsing broke"); - - var wfr2 = new PROT_WireFormatReader(new TH_ThreadQueue(), tablesData); - wfr2.deserialize(data2, data2cb); - }; - - function data2cb(tablesKnown, tablesData) { - for (var i = 0; i < 100; i++) - G_Assert(z, - !tablesData[tableName].exists("http://exists" + i), - "Tables merge broken"); - - G_Assert(z, tablesKnown[tableName].major == "1", "Major parsing broke"); - G_Assert(z, tablesKnown[tableName].minor == "7", "Major parsing broke"); - - var wfr3 = new PROT_WireFormatReader(new TH_ThreadQueue(), tablesData); - var data3 = "[test-white-domain 1.1][mac=" + computedMac + "]\n" + - set3data; - wfr3.deserialize(data3, data3cb); - }; - - // Test the MAC stuff - function data3cb(tablesKnown, tablesData) { - G_Assert(z, tablesData["test-white-domain"] != null, - "Didn't get our table back though the mac was correct"); - - // Now do the same thing with the wrong mac - computedMac = "012" + computedMac.substr(3); - var data4 = "[test-foo-domain 1.1][mac=" + computedMac + "]\n" + - set3data; - var wfr4 = new PROT_WireFormatReader(new TH_ThreadQueue(), tablesData); - wfr4.deserialize(data4, data4cb); - } - - // Test the MAC stuff - function data4cb(tablesKnown, tablesData) { - G_Assert(z, !tablesKnown["test-foo-domain"], - "Deserialized though our mac was wrong"); - - G_Assert(z, !tablesData["test-foo-domain"], - "Deserialized though our mac was wrong"); - - testMalformedTables(); - - } - var wfr = new PROT_WireFormatReader(new TH_ThreadQueue()); - wfr.deserialize(data1, data1cb); + G_Debug(z, "PASSED"); } } diff --git a/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js b/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js index 7294d522d14..48bf07e1e70 100644 --- a/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js +++ b/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js @@ -121,18 +121,18 @@ PROT_XMLFetcher.prototype = { // headers) when we try to read the response. Mask the exception // by returning null response. // TODO maybe masking this should be an option? + var responseText = null; try { G_Debug(this, "xml fetch status code: \"" + fetcher._request.status + "\""); - if (fetcher._callback) - fetcher._callback(fetcher._request.responseText); + var responseText = fetcher._request.responseText; } catch(e) { G_Debug(this, "Caught exception trying to read xmlhttprequest " + "status/response."); G_Debug(this, e); - if (fetcher._callback) - fetcher._callback(null); } + if (fetcher._callback) + fetcher._callback(responseText); } }; diff --git a/mozilla/toolkit/components/url-classifier/jar.mn b/mozilla/toolkit/components/url-classifier/jar.mn index 5a75b0a06e9..4ecdde0bd3f 100644 --- a/mozilla/toolkit/components/url-classifier/jar.mn +++ b/mozilla/toolkit/components/url-classifier/jar.mn @@ -1,7 +1,6 @@ toolkit.jar: + content/global/url-classifier/application.js (content/application.js) + content/global/url-classifier/enchash-decrypter.js (content/enchash-decrypter.js) -+ content/global/url-classifier/globalstore.js (content/globalstore.js) + content/global/url-classifier/listmanager.js (content/listmanager.js) + content/global/url-classifier/list-warden.js (content/list-warden.js) + content/global/url-classifier/map.js (content/map.js) diff --git a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableDomain.js b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableDomain.js index 7d6ee70ed19..7ec723f528b 100644 --- a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableDomain.js +++ b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableDomain.js @@ -16,7 +16,7 @@ const LIB_FILES = [ ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - dump('*** loading subscript ' + libFile + '\n'); + //dump('*** loading subscript ' + libFile + '\n'); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript(libFile); diff --git a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js index de9105a6023..fd6492efa9b 100644 --- a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js +++ b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableEnchash.js @@ -20,7 +20,7 @@ const LIB_FILES = [ ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - dump('*** loading subscript ' + libFile + '\n'); + //dump('*** loading subscript ' + libFile + '\n'); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript(libFile); diff --git a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableSite.js b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableSite.js index c9c988e9502..4a950bc8859 100644 --- a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableSite.js +++ b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableSite.js @@ -16,7 +16,7 @@ const LIB_FILES = [ ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - dump('*** loading subscript ' + libFile + '\n'); + //dump('*** loading subscript ' + libFile + '\n'); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript(libFile); diff --git a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableUrl.js b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableUrl.js index c94ee845890..a79684920a9 100644 --- a/mozilla/toolkit/components/url-classifier/src/urlClassifierTableUrl.js +++ b/mozilla/toolkit/components/url-classifier/src/urlClassifierTableUrl.js @@ -17,7 +17,7 @@ const LIB_FILES = [ ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - dump('*** loading subscript ' + libFile + '\n'); + //dump('*** loading subscript ' + libFile + '\n'); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript(libFile); diff --git a/mozilla/toolkit/components/url-classifier/src/urlListManager.js b/mozilla/toolkit/components/url-classifier/src/urlListManager.js index ccb9f54c286..cd3ab530e39 100644 --- a/mozilla/toolkit/components/url-classifier/src/urlListManager.js +++ b/mozilla/toolkit/components/url-classifier/src/urlListManager.js @@ -21,7 +21,6 @@ const LIB_FILES = [ "chrome://global/content/url-classifier/moz/protocol4.js", "chrome://global/content/url-classifier/application.js", - "chrome://global/content/url-classifier/globalstore.js", "chrome://global/content/url-classifier/listmanager.js", "chrome://global/content/url-classifier/url-crypto.js", "chrome://global/content/url-classifier/url-crypto-key-manager.js", // dep url-crypto.js @@ -30,7 +29,7 @@ const LIB_FILES = [ ]; for (var i = 0, libFile; libFile = LIB_FILES[i]; ++i) { - dump('*** loading subscript ' + libFile + '\n'); + //dump('*** loading subscript ' + libFile + '\n'); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript(libFile);