diff --git a/services/sync/modules/engines/addons.js b/services/sync/modules/engines/addons.js index 5ad13b9213b..1221ed91cec 100644 --- a/services/sync/modules/engines/addons.js +++ b/services/sync/modules/engines/addons.js @@ -275,6 +275,8 @@ AddonsStore.prototype = { // Define the add-on types (.type) that we support. _syncableTypes: ["extension", "theme"], + _extensionsPrefs: new Preferences("extensions."), + get reconciler() { return this.engine._reconciler; }, @@ -539,7 +541,8 @@ AddonsStore.prototype = { // 2) Installed in the current profile // 3) Not installed by a foreign entity (i.e. installed by the app) // since they act like global extensions. - // 4) Are installed from AMO + // 4) Is not a hotfix. + // 5) Are installed from AMO // We could represent the test as a complex boolean expression. We go the // verbose route so the failure reason is logged. @@ -568,6 +571,12 @@ AddonsStore.prototype = { return false; } + // Ignore hotfix extensions (bug 741670). The pref may not be defined. + if (this._extensionsPrefs.get("hotfix.id", null) == addon.id) { + this._log.debug(addon.id + " not syncable: is a hotfix."); + return false; + } + // We provide a back door to skip the repository checking of an add-on. // This is utilized by the tests to make testing easier. Users could enable // this, but it would sacrifice security. diff --git a/services/sync/tests/unit/test_addons_store.js b/services/sync/tests/unit/test_addons_store.js index 8ff4dad9f7a..2fbccf19d89 100644 --- a/services/sync/tests/unit/test_addons_store.js +++ b/services/sync/tests/unit/test_addons_store.js @@ -367,6 +367,48 @@ add_test(function test_addon_syncability() { run_next_test(); }); +add_test(function test_ignore_hotfixes() { + _("Ensure that hotfix extensions are ignored."); + + Svc.Prefs.set("addons.ignoreRepositoryChecking", true); + + // A hotfix extension is one that has the id the same as the + // extensions.hotfix.id pref. + let prefs = new Preferences("extensions."); + + let addon = installAddon("test_bootstrap1_1"); + do_check_true(store.isAddonSyncable(addon)); + + let dummy = {}; + const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"]; + for each (let k in KEYS) { + dummy[k] = addon[k]; + } + + // Basic sanity check. + do_check_true(store.isAddonSyncable(dummy)); + + prefs.set("hotfix.id", dummy.id); + do_check_false(store.isAddonSyncable(dummy)); + + // Verify that int values don't throw off checking. + let prefSvc = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService) + .getBranch("extensions."); + // Need to delete pref before changing type. + prefSvc.deleteBranch("hotfix.id"); + prefSvc.setIntPref("hotfix.id", 0xdeadbeef); + + do_check_true(store.isAddonSyncable(dummy)); + + uninstallAddon(addon); + + Svc.Prefs.reset("addons.ignoreRepositoryChecking"); + prefs.reset("hotfix.id"); + + run_next_test(); +}); + add_test(function test_ignore_untrusted_source_uris() { _("Ensures that source URIs from insecure schemes are rejected.");