From 4fb11cd5966461bccc3ed1599b808237be6b0de9 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sat, 10 Feb 2018 02:49:12 -0500 Subject: Move WebExtensions enabled Add-ons Manager --- toolkit/mozapps/extensions/.eslintrc.js | 8 - toolkit/mozapps/extensions/AddonContentPolicy.cpp | 478 - toolkit/mozapps/extensions/AddonContentPolicy.h | 22 - toolkit/mozapps/extensions/AddonManager.jsm | 3674 -------- toolkit/mozapps/extensions/AddonManagerWebAPI.cpp | 171 - toolkit/mozapps/extensions/AddonManagerWebAPI.h | 33 - toolkit/mozapps/extensions/AddonPathService.cpp | 258 - toolkit/mozapps/extensions/AddonPathService.h | 55 - .../mozapps/extensions/ChromeManifestParser.jsm | 157 - toolkit/mozapps/extensions/DeferredSave.jsm | 275 - .../mozapps/extensions/LightweightThemeManager.jsm | 909 -- toolkit/mozapps/extensions/addonManager.js | 296 - toolkit/mozapps/extensions/amContentHandler.js | 100 - toolkit/mozapps/extensions/amIAddonManager.idl | 29 - toolkit/mozapps/extensions/amIAddonPathService.idl | 37 - .../mozapps/extensions/amIWebInstallListener.idl | 134 - toolkit/mozapps/extensions/amIWebInstaller.idl | 82 - toolkit/mozapps/extensions/amInstallTrigger.js | 240 - toolkit/mozapps/extensions/amWebAPI.js | 269 - toolkit/mozapps/extensions/amWebInstallListener.js | 348 - .../extensions/content/OpenH264-license.txt | 59 - toolkit/mozapps/extensions/content/about.js | 103 - toolkit/mozapps/extensions/content/about.xul | 57 - toolkit/mozapps/extensions/content/blocklist.css | 11 - toolkit/mozapps/extensions/content/blocklist.js | 72 - toolkit/mozapps/extensions/content/blocklist.xml | 58 - toolkit/mozapps/extensions/content/blocklist.xul | 46 - toolkit/mozapps/extensions/content/eula.js | 25 - toolkit/mozapps/extensions/content/eula.xul | 35 - toolkit/mozapps/extensions/content/extensions.css | 270 - toolkit/mozapps/extensions/content/extensions.js | 3915 -------- toolkit/mozapps/extensions/content/extensions.xml | 2008 ----- toolkit/mozapps/extensions/content/extensions.xul | 715 -- toolkit/mozapps/extensions/content/gmpPrefs.xul | 8 - toolkit/mozapps/extensions/content/list.js | 165 - toolkit/mozapps/extensions/content/list.xul | 44 - toolkit/mozapps/extensions/content/newaddon.js | 137 - toolkit/mozapps/extensions/content/newaddon.xul | 67 - toolkit/mozapps/extensions/content/pluginPrefs.xul | 20 - toolkit/mozapps/extensions/content/setting.xml | 486 - toolkit/mozapps/extensions/content/update.js | 663 -- toolkit/mozapps/extensions/content/update.xul | 194 - toolkit/mozapps/extensions/content/updateinfo.xsl | 41 - .../extensions/content/xpinstallConfirm.css | 8 - .../mozapps/extensions/content/xpinstallConfirm.js | 196 - .../extensions/content/xpinstallConfirm.xul | 37 - .../mozapps/extensions/content/xpinstallItem.xml | 51 - toolkit/mozapps/extensions/docs/SystemAddons.rst | 224 - toolkit/mozapps/extensions/docs/index.rst | 14 - toolkit/mozapps/extensions/extensions.manifest | 27 - .../extensions/internal/APIExtensionBootstrap.js | 39 - .../mozapps/extensions/internal/AddonConstants.jsm | 31 - .../mozapps/extensions/internal/AddonLogging.jsm | 192 - .../extensions/internal/AddonRepository.jsm | 1988 ----- .../internal/AddonRepository_SQLiteMigrator.jsm | 522 -- .../mozapps/extensions/internal/AddonTestUtils.jsm | 1231 --- .../extensions/internal/AddonUpdateChecker.jsm | 934 -- toolkit/mozapps/extensions/internal/Content.js | 38 - .../extensions/internal/E10SAddonsRollout.jsm | 982 --- .../mozapps/extensions/internal/GMPProvider.jsm | 699 -- .../internal/LightweightThemeImageOptimizer.jsm | 180 - .../mozapps/extensions/internal/PluginProvider.jsm | 600 -- .../extensions/internal/ProductAddonChecker.jsm | 467 - .../internal/SpellCheckDictionaryBootstrap.js | 17 - .../extensions/internal/WebExtensionBootstrap.js | 39 - .../mozapps/extensions/internal/XPIProvider.jsm | 9305 -------------------- .../extensions/internal/XPIProviderUtils.js | 2255 ----- toolkit/mozapps/extensions/internal/moz.build | 36 - toolkit/mozapps/extensions/jar.mn | 35 - toolkit/mozapps/extensions/moz.build | 66 - toolkit/mozapps/extensions/nsBlocklistService.js | 1667 ---- .../extensions/nsBlocklistServiceContent.js | 113 - .../extensions/test/AddonManagerTesting.jsm | 115 - toolkit/mozapps/extensions/test/Makefile.in | 20 - .../test/addons/blocklist_hard1_1/install.rdf | 18 - .../test/addons/blocklist_hard1_2/install.rdf | 18 - .../test/addons/blocklist_hard1_3/install.rdf | 18 - .../test/addons/blocklist_regexp1_1/install.rdf | 18 - .../test/addons/blocklist_regexp1_2/install.rdf | 18 - .../test/addons/blocklist_regexp1_3/install.rdf | 18 - .../test/addons/blocklist_soft1_1/install.rdf | 18 - .../test/addons/blocklist_soft1_2/install.rdf | 18 - .../test/addons/blocklist_soft1_3/install.rdf | 18 - .../test/addons/blocklist_soft2_1/install.rdf | 18 - .../test/addons/blocklist_soft2_2/install.rdf | 18 - .../test/addons/blocklist_soft2_3/install.rdf | 18 - .../test/addons/blocklist_soft3_1/install.rdf | 18 - .../test/addons/blocklist_soft3_2/install.rdf | 18 - .../test/addons/blocklist_soft3_3/install.rdf | 18 - .../test/addons/blocklist_soft4_1/install.rdf | 18 - .../test/addons/blocklist_soft4_2/install.rdf | 18 - .../test/addons/blocklist_soft4_3/install.rdf | 18 - .../test/addons/blocklist_soft5_1/install.rdf | 19 - .../test/addons/blocklist_soft5_2/install.rdf | 19 - .../test/addons/blocklist_soft5_3/install.rdf | 19 - .../test/addons/bootstrap_globals/bootstrap.js | 29 - .../test/addons/bootstrap_globals/install.rdf | 23 - .../extensions/test/addons/min1max1/install.rdf | 22 - .../extensions/test/addons/min1max2/install.rdf | 22 - .../extensions/test/addons/min1max3/install.rdf | 22 - .../extensions/test/addons/min1max3b/install.rdf | 22 - .../test/addons/override1x2-1x3/install.rdf | 23 - .../test/addons/test_AddonRepository_1/install.rdf | 33 - .../test/addons/test_AddonRepository_2/install.rdf | 23 - .../test/addons/test_AddonRepository_3/icon.png | 1 - .../test/addons/test_AddonRepository_3/install.rdf | 23 - .../test/addons/test_AddonRepository_3/preview.png | 1 - .../test/addons/test_bootstrap1_1/bootstrap.js | 1 - .../test/addons/test_bootstrap1_1/install.rdf | 28 - .../test/addons/test_bootstrap1_1/version.jsm | 3 - .../test/addons/test_bootstrap1_2/bootstrap.js | 1 - .../test/addons/test_bootstrap1_2/install.rdf | 24 - .../test/addons/test_bootstrap1_2/version.jsm | 3 - .../test/addons/test_bootstrap1_3/bootstrap.js | 1 - .../test/addons/test_bootstrap1_3/install.rdf | 24 - .../test/addons/test_bootstrap1_3/version.jsm | 3 - .../test/addons/test_bootstrap1_4/install.rdf | 23 - .../test/addons/test_bootstrap2_1/bootstrap.js | 1 - .../test/addons/test_bootstrap2_1/install.rdf | 28 - .../test/addons/test_bootstrap_const/bootstrap.js | 5 - .../test/addons/test_bootstrap_const/install.rdf | 24 - .../test/addons/test_bug299716_2/install.rdf | 30 - .../test/addons/test_bug299716_a_1/install.rdf | 21 - .../test/addons/test_bug299716_a_2/install.rdf | 21 - .../test/addons/test_bug299716_b_1/install.rdf | 20 - .../test/addons/test_bug299716_b_2/install.rdf | 20 - .../test/addons/test_bug299716_c_1/install.rdf | 30 - .../test/addons/test_bug299716_c_2/install.rdf | 30 - .../test/addons/test_bug299716_d_1/install.rdf | 30 - .../test/addons/test_bug299716_d_2/install.rdf | 30 - .../test/addons/test_bug299716_e_1/install.rdf | 30 - .../test/addons/test_bug299716_e_2/install.rdf | 30 - .../test/addons/test_bug299716_f_1/install.rdf | 30 - .../test/addons/test_bug299716_f_2/install.rdf | 30 - .../test/addons/test_bug299716_g_1/install.rdf | 21 - .../test/addons/test_bug299716_g_2/install.rdf | 21 - .../test/addons/test_bug324121_1/install.rdf | 25 - .../test/addons/test_bug324121_2/install.rdf | 25 - .../test/addons/test_bug324121_3/install.rdf | 25 - .../test/addons/test_bug324121_4/install.rdf | 25 - .../test/addons/test_bug324121_5/install.rdf | 25 - .../test/addons/test_bug324121_6/install.rdf | 25 - .../test/addons/test_bug324121_7/install.rdf | 25 - .../test/addons/test_bug324121_8/install.rdf | 25 - .../test/addons/test_bug324121_9/install.rdf | 25 - .../test/addons/test_bug335238_1/install.rdf | 22 - .../test/addons/test_bug335238_2/install.rdf | 30 - .../test/addons/test_bug335238_3/install.rdf | 30 - .../test/addons/test_bug335238_4/install.rdf | 30 - .../test/addons/test_bug371495/install.rdf | 26 - .../test/addons/test_bug394300_1/install.rdf | 22 - .../test/addons/test_bug394300_2/install.rdf | 22 - .../test/addons/test_bug397778/install.rdf | 78 - .../test/addons/test_bug425657/install.rdf | 17 - .../test/addons/test_bug470377_1/install.rdf | 17 - .../test/addons/test_bug470377_2/install.rdf | 17 - .../test/addons/test_bug470377_3/install.rdf | 17 - .../test/addons/test_bug470377_4/install.rdf | 17 - .../test/addons/test_bug470377_5/install.rdf | 17 - .../test/addons/test_bug521905/install.rdf | 22 - .../test/addons/test_bug567173/install.rdf | 22 - .../test/addons/test_bug567184/bootstrap.js | 7 - .../test/addons/test_bug567184/install.rdf | 24 - .../test/addons/test_bug587088_1/install.rdf | 22 - .../test/addons/test_bug587088_1/testfile | 1 - .../test/addons/test_bug587088_1/testfile1 | 0 .../test/addons/test_bug587088_2/install.rdf | 22 - .../test/addons/test_bug587088_2/testfile | 1 - .../test/addons/test_bug587088_2/testfile2 | 0 .../test/addons/test_bug594058/directory/file1 | 0 .../test/addons/test_bug594058/install.rdf | 21 - .../test/addons/test_bug595573/install.rdf | 24 - .../test/addons/test_bug655254/install.rdf | 18 - .../test/addons/test_bug655254_2/bootstrap.js | 9 - .../test/addons/test_bug655254_2/install.rdf | 19 - .../test/addons/test_bug659772/install.rdf | 24 - .../test/addons/test_bug675371/chrome.manifest | 1 - .../test/addons/test_bug675371/install.rdf | 24 - .../extensions/test/addons/test_bug675371/test.js | 1 - .../test/addons/test_bug740612_1/bootstrap.js | 1 - .../test/addons/test_bug740612_1/install.rdf | 24 - .../test/addons/test_bug740612_2/bootstrap.js | 23 - .../test/addons/test_bug740612_2/install.rdf | 24 - .../test/addons/test_bug757663/install.rdf | 24 - .../test/addons/test_cacheflush1/install.rdf | 22 - .../test/addons/test_cacheflush2/install.rdf | 23 - .../addons/test_chromemanifest_1/chrome.manifest | 6 - .../test/addons/test_chromemanifest_1/install.rdf | 23 - .../addons/test_chromemanifest_2/chrome.manifest | 7 - .../test/addons/test_chromemanifest_2/install.rdf | 24 - .../addons/test_chromemanifest_3/chrome.manifest | 9 - .../test/addons/test_chromemanifest_3/inner.jar | Bin 180 -> 0 bytes .../test/addons/test_chromemanifest_3/install.rdf | 24 - .../addons/test_chromemanifest_4/chrome.manifest | 6 - .../components/components.manifest | 2 - .../components/other/something.manifest | 1 - .../test/addons/test_chromemanifest_4/install.rdf | 24 - .../addons/test_chromemanifest_5/chrome.manifest | 7 - .../test/addons/test_chromemanifest_5/install.rdf | 24 - .../addons/test_chromemanifest_6/chrome.manifest | 1 - .../test/addons/test_chromemanifest_6/install.rdf | 24 - .../test/addons/test_data_directory/install.rdf | 22 - .../test/addons/test_db_sanity_1_1/install.rdf | 58 - .../test/addons/test_db_sanity_1_2/install.rdf | 59 - .../test_delay_update_complete_v2/bootstrap.js | 10 - .../test_delay_update_complete_v2/install.rdf | 27 - .../manifest.json | 10 - .../addons/test_delay_update_defer_v2/bootstrap.js | 10 - .../addons/test_delay_update_defer_v2/install.rdf | 27 - .../manifest.json | 10 - .../test_delay_update_ignore_v2/bootstrap.js | 8 - .../addons/test_delay_update_ignore_v2/install.rdf | 28 - .../manifest.json | 10 - .../test/addons/test_dictionary/chrome.manifest | 1 - .../addons/test_dictionary/dictionaries/ab-CD.dic | 2 - .../test/addons/test_dictionary/install.rdf | 25 - .../test_dictionary_2/dictionaries/ab-CD.dic | 2 - .../test/addons/test_dictionary_2/install.rdf | 24 - .../test/addons/test_dictionary_3/install.rdf | 25 - .../test/addons/test_dictionary_4/install.rdf | 24 - .../test/addons/test_dictionary_5/install.rdf | 25 - .../test/addons/test_distribution1_2/install.rdf | 23 - .../test/addons/test_experiment1/bootstrap.js | 1 - .../test/addons/test_experiment1/install.rdf | 16 - .../test/addons/test_filepointer/install.rdf | 22 - .../test/addons/test_getresource/icon.png | 1 - .../test/addons/test_getresource/install.rdf | 23 - .../addons/test_getresource/subdir/subfile.txt | 1 - .../test/addons/test_hotfix_1/install.rdf | 23 - .../test/addons/test_hotfix_2/install.rdf | 23 - .../extensions/test/addons/test_install1/icon.png | 1 - .../test/addons/test_install1/icon64.png | 1 - .../test/addons/test_install1/install.rdf | 24 - .../test/addons/test_install2_1/icon.png | 1 - .../test/addons/test_install2_1/install.rdf | 24 - .../test/addons/test_install2_2/install.rdf | 24 - .../test/addons/test_install3/install.rdf | 27 - .../test/addons/test_install4/addon4.xpi | Bin 509 -> 0 bytes .../test/addons/test_install4/addon5.jar | Bin 512 -> 0 bytes .../test/addons/test_install4/addon6.xpi | Bin 512 -> 0 bytes .../test/addons/test_install4/addon7.jar | Bin 512 -> 0 bytes .../test/addons/test_install4/badaddon.jar | 1 - .../test/addons/test_install4/badaddon.xpi | 1 - .../extensions/test/addons/test_install4/icon.png | 1 - .../test/addons/test_install4/install.rdf | 10 - .../test/addons/test_install5/chrome.manifest | 1 - .../test/addons/test_install5/install.rdf | 26 - .../test/addons/test_install6/install.rdf | 24 - .../test/addons/test_install7/addon1.xpi | 1 - .../test/addons/test_install7/addon2.xpi | 1 - .../test/addons/test_install7/install.rdf | 10 - .../test/addons/test_install8/install.rdf | 10 - .../test/addons/test_jetpack/bootstrap.js | 17 - .../test/addons/test_jetpack/harness-options.json | 1 - .../test/addons/test_jetpack/install.rdf | 28 - .../test/addons/test_langpack/chrome.manifest | 1 - .../test/addons/test_langpack/install.rdf | 23 - .../extensions/test/addons/test_locale/install.rdf | 61 - .../test/addons/test_locked2_5/install.rdf | 23 - .../test/addons/test_locked2_6/install.rdf | 23 - .../test/addons/test_migrate4_6/install.rdf | 23 - .../test/addons/test_migrate4_7/install.rdf | 23 - .../test/addons/test_migrate6/install.rdf | 23 - .../test/addons/test_migrate7/install.rdf | 24 - .../test/addons/test_migrate8/chrome.manifest | 6 - .../test/addons/test_migrate8/install.rdf | 24 - .../test/addons/test_migrate9/install.rdf | 26 - .../test/addons/test_symbol/bootstrap.js | 62 - .../extensions/test/addons/test_symbol/install.rdf | 28 - .../extensions/test/addons/test_theme/install.rdf | 26 - .../extensions/test/addons/test_theme/preview.png | 1 - .../test/addons/test_undoincompatible/bootstrap.js | 1 - .../test/addons/test_undoincompatible/install.rdf | 28 - .../test/addons/test_undouninstall1/bootstrap.js | 1 - .../test/addons/test_undouninstall1/install.rdf | 28 - .../extensions/test/addons/test_update/install.rdf | 23 - .../test/addons/test_update12/install.rdf | 23 - .../test/addons/test_update8/install.rdf | 23 - .../test/addons/test_update_multi1/bootstrap.js | 5 - .../test/addons/test_update_multi1/install.rdf | 16 - .../test/addons/test_update_multi2/addon.xpi | Bin 693 -> 0 bytes .../test/addons/test_update_multi2/install.rdf | 9 - .../test/addons/test_updateid1/bootstrap.js | 5 - .../test/addons/test_updateid1/install.rdf | 16 - .../test/addons/test_updateid2/bootstrap.js | 5 - .../test/addons/test_updateid2/install.rdf | 16 - .../test/addons/upgradeable1x2-3_1/install.rdf | 22 - .../test/addons/upgradeable1x2-3_2/install.rdf | 22 - .../test/addons/webextension_1/chrome.manifest | 1 - .../test/addons/webextension_1/manifest.json | 14 - .../test/addons/webextension_2/install.rdf | 30 - .../test/addons/webextension_2/manifest.json | 10 - .../webextension_3/_locales/en/messages.json | 10 - .../webextension_3/_locales/fr/messages.json | 10 - .../test/addons/webextension_3/manifest.json | 12 - .../mozapps/extensions/test/browser/.eslintrc.js | 7 - .../extensions/test/browser/addon_about.xul | 6 - .../extensions/test/browser/addon_prefs.xul | 6 - .../test/browser/addons/browser_bug557956_1.xpi | Bin 4426 -> 0 bytes .../browser/addons/browser_bug557956_1/install.rdf | 31 - .../test/browser/addons/browser_bug557956_10.xpi | Bin 4425 -> 0 bytes .../addons/browser_bug557956_10/install.rdf | 31 - .../test/browser/addons/browser_bug557956_2.xpi | Bin 4427 -> 0 bytes .../browser/addons/browser_bug557956_2/install.rdf | 31 - .../test/browser/addons/browser_bug557956_3.xpi | Bin 4425 -> 0 bytes .../browser/addons/browser_bug557956_3/install.rdf | 31 - .../test/browser/addons/browser_bug557956_4.xpi | Bin 4432 -> 0 bytes .../browser/addons/browser_bug557956_4/install.rdf | 31 - .../test/browser/addons/browser_bug557956_5.xpi | Bin 4427 -> 0 bytes .../browser/addons/browser_bug557956_5/install.rdf | 31 - .../test/browser/addons/browser_bug557956_6.xpi | Bin 4424 -> 0 bytes .../browser/addons/browser_bug557956_6/install.rdf | 31 - .../test/browser/addons/browser_bug557956_7.xpi | Bin 4424 -> 0 bytes .../browser/addons/browser_bug557956_7/install.rdf | 31 - .../test/browser/addons/browser_bug557956_8_1.xpi | Bin 4427 -> 0 bytes .../addons/browser_bug557956_8_1/install.rdf | 31 - .../test/browser/addons/browser_bug557956_9_1.xpi | Bin 4421 -> 0 bytes .../addons/browser_bug557956_9_1/install.rdf | 31 - .../test/browser/addons/browser_bug567127_1.xpi | Bin 4425 -> 0 bytes .../browser/addons/browser_bug567127_1/install.rdf | 30 - .../test/browser/addons/browser_bug567127_2.xpi | Bin 4427 -> 0 bytes .../browser/addons/browser_bug567127_2/install.rdf | 30 - .../test/browser/addons/browser_bug596336_1.xpi | Bin 4449 -> 0 bytes .../browser/addons/browser_bug596336_1/install.rdf | 31 - .../test/browser/addons/browser_bug596336_2.xpi | Bin 4440 -> 0 bytes .../browser/addons/browser_bug596336_2/install.rdf | 31 - .../test/browser/addons/browser_dragdrop1.xpi | Bin 4424 -> 0 bytes .../browser/addons/browser_dragdrop1/install.rdf | 30 - .../test/browser/addons/browser_dragdrop2.xpi | Bin 4420 -> 0 bytes .../browser/addons/browser_dragdrop2/install.rdf | 30 - .../test/browser/addons/browser_experiment1.xpi | Bin 4328 -> 0 bytes .../browser/addons/browser_experiment1/install.rdf | 16 - .../browser/addons/browser_inlinesettings1.xpi | Bin 5811 -> 0 bytes .../addons/browser_inlinesettings1/bootstrap.js | 8 - .../addons/browser_inlinesettings1/chrome.manifest | 1 - .../addons/browser_inlinesettings1/install.rdf | 27 - .../addons/browser_inlinesettings1/options.xul | 23 - .../addons/browser_inlinesettings1/settings.dtd | 1 - .../addons/browser_inlinesettings1_custom.xpi | Bin 6155 -> 0 bytes .../browser_inlinesettings1_custom/binding.xml | 19 - .../browser_inlinesettings1_custom/bootstrap.js | 8 - .../browser_inlinesettings1_custom/chrome.manifest | 2 - .../browser_inlinesettings1_custom/install.rdf | 27 - .../browser_inlinesettings1_custom/options.xul | 5 - .../browser_inlinesettings1_custom/string.dtd | 1 - .../addons/browser_inlinesettings1_info.xpi | Bin 5279 -> 0 bytes .../browser_inlinesettings1_info/bootstrap.js | 8 - .../browser_inlinesettings1_info/install.rdf | 28 - .../browser_inlinesettings1_info/options.xul | 19 - .../test/browser/addons/browser_install1_1.xpi | Bin 4489 -> 0 bytes .../browser/addons/browser_install1_1/install.rdf | 32 - .../test/browser/addons/browser_install1_2.xpi | Bin 4415 -> 0 bytes .../browser/addons/browser_install1_2/install.rdf | 30 - .../test/browser/addons/browser_installssl.xpi | Bin 4430 -> 0 bytes .../browser/addons/browser_installssl/install.rdf | 30 - .../test/browser/addons/browser_searching.xpi | Bin 4808 -> 0 bytes .../browser/addons/browser_searching/bootstrap.js | 9 - .../browser/addons/browser_searching/install.rdf | 25 - .../test/browser/addons/browser_update1_1.xpi | Bin 5479 -> 0 bytes .../browser/addons/browser_update1_1/bootstrap.js | 12 - .../addons/browser_update1_1/chrome.manifest | 1 - .../addons/browser_update1_1/frame-script.js | 6 - .../browser/addons/browser_update1_1/install.rdf | 31 - .../test/browser/addons/browser_update1_2.xpi | Bin 5481 -> 0 bytes .../browser/addons/browser_update1_2/bootstrap.js | 12 - .../addons/browser_update1_2/chrome.manifest | 1 - .../addons/browser_update1_2/frame-script.js | 6 - .../browser/addons/browser_update1_2/install.rdf | 31 - .../test/browser/addons/browser_webapi_install.xpi | Bin 4782 -> 0 bytes .../addons/browser_webapi_install/bootstrap.js | 9 - .../addons/browser_webapi_install/install.rdf | 29 - .../test/browser/addons/options_signed.xpi | Bin 4560 -> 0 bytes .../browser/addons/options_signed/manifest.json | 11 - .../browser/addons/options_signed/options.html | 9 - .../extensions/test/browser/blockNoPlugins.xml | 7 - .../extensions/test/browser/blockPluginHard.xml | 11 - .../extensions/test/browser/browser-common.ini | 67 - .../extensions/test/browser/browser-window.ini | 52 - .../mozapps/extensions/test/browser/browser.ini | 75 - .../extensions/test/browser/browser_CTP_plugins.js | 172 - .../extensions/test/browser/browser_about.js | 84 - .../browser/browser_addonrepository_performance.js | 99 - .../extensions/test/browser/browser_bug523784.js | 120 - .../extensions/test/browser/browser_bug557943.js | 80 - .../extensions/test/browser/browser_bug557956.js | 524 -- .../extensions/test/browser/browser_bug557956.rdf | 310 - .../extensions/test/browser/browser_bug557956.xml | 20 - .../test/browser/browser_bug557956_8_2.xpi | Bin 4438 -> 0 bytes .../test/browser/browser_bug557956_9_2.xpi | Bin 4426 -> 0 bytes .../extensions/test/browser/browser_bug562797.js | 975 -- .../extensions/test/browser/browser_bug562854.js | 129 - .../extensions/test/browser/browser_bug562890.js | 78 - .../extensions/test/browser/browser_bug562899.js | 88 - .../extensions/test/browser/browser_bug562992.js | 70 - .../extensions/test/browser/browser_bug567127.js | 136 - .../extensions/test/browser/browser_bug567137.js | 40 - .../extensions/test/browser/browser_bug570760.js | 44 - .../extensions/test/browser/browser_bug572561.js | 99 - .../extensions/test/browser/browser_bug573062.js | 116 - .../extensions/test/browser/browser_bug577990.js | 132 - .../extensions/test/browser/browser_bug580298.js | 98 - .../extensions/test/browser/browser_bug581076.js | 132 - .../extensions/test/browser/browser_bug586574.js | 286 - .../extensions/test/browser/browser_bug587970.js | 180 - .../extensions/test/browser/browser_bug590347.js | 121 - .../extensions/test/browser/browser_bug591465.js | 512 -- .../extensions/test/browser/browser_bug591465.xml | 35 - .../extensions/test/browser/browser_bug591663.js | 161 - .../extensions/test/browser/browser_bug593535.js | 119 - .../extensions/test/browser/browser_bug593535.xml | 34 - .../extensions/test/browser/browser_bug596336.js | 156 - .../extensions/test/browser/browser_bug608316.js | 65 - .../extensions/test/browser/browser_bug610764.js | 34 - .../extensions/test/browser/browser_bug616841.js | 21 - .../extensions/test/browser/browser_bug618502.js | 44 - .../extensions/test/browser/browser_bug679604.js | 29 - .../extensions/test/browser/browser_bug714593.js | 140 - .../test/browser/browser_cancelCompatCheck.js | 462 - .../browser/browser_checkAddonCompatibility.js | 34 - .../extensions/test/browser/browser_details.js | 1053 --- .../extensions/test/browser/browser_discovery.js | 651 -- .../test/browser/browser_discovery_install.js | 133 - .../extensions/test/browser/browser_dragdrop.js | 234 - .../extensions/test/browser/browser_eula.js | 85 - .../extensions/test/browser/browser_eula.xml | 35 - .../extensions/test/browser/browser_experiments.js | 654 -- .../test/browser/browser_globalwarnings.js | 63 - .../extensions/test/browser/browser_gmpProvider.js | 418 - .../extensions/test/browser/browser_hotfix.js | 171 - .../test/browser/browser_inlinesettings.js | 680 -- .../test/browser/browser_inlinesettings_browser.js | 207 - .../test/browser/browser_inlinesettings_custom.js | 92 - .../test/browser/browser_inlinesettings_info.js | 574 -- .../extensions/test/browser/browser_install.js | 312 - .../extensions/test/browser/browser_install.rdf | 27 - .../test/browser/browser_install.rdf^headers^ | 1 - .../extensions/test/browser/browser_install.xml | 34 - .../extensions/test/browser/browser_install1_3.xpi | Bin 4419 -> 0 bytes .../extensions/test/browser/browser_installssl.js | 374 - .../extensions/test/browser/browser_list.js | 956 -- .../test/browser/browser_manualupdates.js | 246 - .../test/browser/browser_metadataTimeout.js | 114 - .../extensions/test/browser/browser_newaddon.js | 232 - .../extensions/test/browser/browser_openDialog.js | 173 - .../browser/browser_plugin_enabled_state_locked.js | 124 - .../extensions/test/browser/browser_pluginprefs.js | 61 - .../extensions/test/browser/browser_purchase.js | 197 - .../extensions/test/browser/browser_purchase.xml | 180 - .../test/browser/browser_recentupdates.js | 125 - .../extensions/test/browser/browser_searching.js | 698 -- .../extensions/test/browser/browser_searching.xml | 277 - .../test/browser/browser_searching_empty.xml | 3 - .../extensions/test/browser/browser_sorting.js | 372 - .../test/browser/browser_sorting_plugins.js | 95 - .../test/browser/browser_system_addons_are_e10s.js | 13 - .../extensions/test/browser/browser_tabsettings.js | 100 - .../test/browser/browser_task_next_test.js | 17 - .../extensions/test/browser/browser_types.js | 473 - .../test/browser/browser_uninstalling.js | 1098 --- .../extensions/test/browser/browser_update.js | 53 - .../extensions/test/browser/browser_updateid.js | 84 - .../extensions/test/browser/browser_updatessl.js | 370 - .../extensions/test/browser/browser_updatessl.rdf | 25 - .../test/browser/browser_updatessl.rdf^headers^ | 1 - .../extensions/test/browser/browser_webapi.js | 106 - .../test/browser/browser_webapi_access.js | 127 - .../test/browser/browser_webapi_addon_listener.js | 174 - .../test/browser/browser_webapi_enable.js | 62 - .../test/browser/browser_webapi_install.js | 311 - .../test/browser/browser_webapi_uninstall.js | 51 - .../test/browser/browser_webext_options.js | 70 - .../extensions/test/browser/cancelCompatCheck.sjs | 43 - .../mozapps/extensions/test/browser/discovery.html | 10 - .../extensions/test/browser/discovery_frame.html | 6 - .../extensions/test/browser/discovery_install.html | 19 - toolkit/mozapps/extensions/test/browser/head.js | 1468 --- .../extensions/test/browser/more_options.xul | 32 - toolkit/mozapps/extensions/test/browser/moz.build | 10 - .../mozapps/extensions/test/browser/options.xul | 12 - .../extensions/test/browser/plugin_test.html | 7 - .../mozapps/extensions/test/browser/redirect.sjs | 5 - .../extensions/test/browser/releaseNotes.xhtml | 15 - .../extensions/test/browser/signed_hotfix.rdf | 26 - .../extensions/test/browser/signed_hotfix.xpi | Bin 2745 -> 0 bytes .../extensions/test/browser/unsigned_hotfix.rdf | 26 - .../extensions/test/browser/unsigned_hotfix.xpi | Bin 560 -> 0 bytes .../test/browser/webapi_addon_listener.html | 30 - .../test/browser/webapi_checkavailable.html | 13 - .../test/browser/webapi_checkchromeframe.xul | 6 - .../test/browser/webapi_checkframed.html | 7 - .../test/browser/webapi_checknavigatedwindow.html | 28 - .../mozapps/extensions/test/mochitest/.eslintrc.js | 7 - .../extensions/test/mochitest/file_bug687194.xpi | Bin 5659 -> 0 bytes .../extensions/test/mochitest/file_empty.html | 2 - .../extensions/test/mochitest/mochitest.ini | 9 - .../extensions/test/mochitest/test_bug609794.html | 27 - .../extensions/test/mochitest/test_bug687194.html | 133 - .../extensions/test/mochitest/test_bug887098.html | 52 - toolkit/mozapps/extensions/test/moz.build | 19 - .../mozapps/extensions/test/xpcshell/.eslintrc.js | 7 - .../test/xpcshell/data/BootstrapMonitor.jsm | 30 - .../xpcshell/data/blocklistchange/addon_change.xml | 31 - .../data/blocklistchange/addon_update1.rdf | 144 - .../data/blocklistchange/addon_update2.rdf | 144 - .../data/blocklistchange/addon_update3.rdf | 144 - .../xpcshell/data/blocklistchange/app_update.xml | 62 - .../data/blocklistchange/blocklist_update1.xml | 3 - .../data/blocklistchange/blocklist_update2.xml | 26 - .../data/blocklistchange/manual_update.xml | 27 - .../test/xpcshell/data/bug455906_block.xml | 18 - .../test/xpcshell/data/bug455906_empty.xml | 7 - .../test/xpcshell/data/bug455906_start.xml | 30 - .../test/xpcshell/data/bug455906_warn.xml | 33 - .../extensions/test/xpcshell/data/corrupt.xpi | 1 - .../extensions/test/xpcshell/data/corruptfile.xpi | Bin 633 -> 0 bytes .../extensions/test/xpcshell/data/empty.xpi | Bin 197 -> 0 bytes .../test/xpcshell/data/from_sources/bootstrap.js | 1 - .../test/xpcshell/data/from_sources/install.rdf | 28 - .../test/xpcshell/data/pluginInfoURL_block.xml | 45 - .../test/xpcshell/data/productaddons/bad.txt | 1 - .../test/xpcshell/data/productaddons/bad.xml | 3 - .../test/xpcshell/data/productaddons/bad2.xml | 3 - .../test/xpcshell/data/productaddons/empty.xml | 5 - .../test/xpcshell/data/productaddons/good.xml | 11 - .../test/xpcshell/data/productaddons/missing.xml | 3 - .../test/xpcshell/data/productaddons/unsigned.xpi | Bin 452 -> 0 bytes .../data/signing_checks/bootstrap_1/bootstrap.js | 29 - .../data/signing_checks/bootstrap_1/install.rdf | 24 - .../data/signing_checks/bootstrap_1/test.txt | 1 - .../data/signing_checks/bootstrap_2/bootstrap.js | 29 - .../data/signing_checks/bootstrap_2/install.rdf | 24 - .../data/signing_checks/bootstrap_2/test.txt | 1 - .../xpcshell/data/signing_checks/hotfix_badid.xpi | Bin 5151 -> 0 bytes .../xpcshell/data/signing_checks/hotfix_broken.xpi | Bin 5298 -> 0 bytes .../xpcshell/data/signing_checks/hotfix_good.xpi | Bin 5158 -> 0 bytes .../xpcshell/data/signing_checks/long_63_hash.xpi | Bin 4471 -> 0 bytes .../xpcshell/data/signing_checks/long_63_plain.xpi | Bin 4433 -> 0 bytes .../xpcshell/data/signing_checks/long_64_hash.xpi | Bin 4474 -> 0 bytes .../xpcshell/data/signing_checks/long_64_plain.xpi | Bin 4436 -> 0 bytes .../xpcshell/data/signing_checks/long_65_hash.xpi | Bin 4487 -> 0 bytes .../xpcshell/data/signing_checks/multi_badid.xpi | Bin 6443 -> 0 bytes .../xpcshell/data/signing_checks/multi_broken.xpi | Bin 6563 -> 0 bytes .../xpcshell/data/signing_checks/multi_signed.xpi | Bin 6425 -> 0 bytes .../data/signing_checks/multi_unsigned.xpi | Bin 2436 -> 0 bytes .../data/signing_checks/nonbootstrap_1/install.rdf | 23 - .../data/signing_checks/nonbootstrap_1/test.txt | 1 - .../data/signing_checks/nonbootstrap_2/install.rdf | 23 - .../data/signing_checks/nonbootstrap_2/test.txt | 1 - .../signing_checks/preliminary_bootstrap_2.xpi | Bin 5161 -> 0 bytes .../data/signing_checks/signed_bootstrap_1.xpi | Bin 5150 -> 0 bytes .../data/signing_checks/signed_bootstrap_2.xpi | Bin 5149 -> 0 bytes .../signing_checks/signed_bootstrap_badid_2.xpi | Bin 5155 -> 0 bytes .../data/signing_checks/signed_nonbootstrap_2.xpi | Bin 4627 -> 0 bytes .../signing_checks/signed_nonbootstrap_badid_2.xpi | Bin 4634 -> 0 bytes .../data/signing_checks/unsigned_bootstrap_2.xpi | Bin 1156 -> 0 bytes .../signing_checks/unsigned_nonbootstrap_2.xpi | Bin 691 -> 0 bytes .../test/xpcshell/data/system_addons/bootstrap.js | 1 - .../test/xpcshell/data/system_addons/system1_1.xpi | Bin 4692 -> 0 bytes .../data/system_addons/system1_1_badcert.xpi | Bin 4808 -> 0 bytes .../test/xpcshell/data/system_addons/system1_2.xpi | Bin 4695 -> 0 bytes .../test/xpcshell/data/system_addons/system2_1.xpi | Bin 4692 -> 0 bytes .../test/xpcshell/data/system_addons/system2_2.xpi | Bin 4695 -> 0 bytes .../test/xpcshell/data/system_addons/system2_3.xpi | Bin 4697 -> 0 bytes .../test/xpcshell/data/system_addons/system3_1.xpi | Bin 4689 -> 0 bytes .../test/xpcshell/data/system_addons/system3_2.xpi | Bin 4691 -> 0 bytes .../test/xpcshell/data/system_addons/system3_3.xpi | Bin 4693 -> 0 bytes .../test/xpcshell/data/system_addons/system4_1.xpi | Bin 4692 -> 0 bytes .../test/xpcshell/data/system_addons/system5_1.xpi | Bin 4691 -> 0 bytes .../data/system_addons/system6_1_unpack.xpi | Bin 4708 -> 0 bytes .../data/system_addons/system6_2_notBootstrap.xpi | Bin 4682 -> 0 bytes .../system_addons/system6_3_notMultiprocess.xpi | Bin 4675 -> 0 bytes .../data/system_addons/system_delay_complete.xpi | Bin 5090 -> 0 bytes .../data/system_addons/system_delay_complete_2.xpi | Bin 4706 -> 0 bytes .../data/system_addons/system_delay_defer.xpi | Bin 5095 -> 0 bytes .../data/system_addons/system_delay_defer_2.xpi | Bin 4701 -> 0 bytes .../data/system_addons/system_delay_defer_also.xpi | Bin 5117 -> 0 bytes .../system_addons/system_delay_defer_also_2.xpi | Bin 4716 -> 0 bytes .../data/system_addons/system_delay_ignore.xpi | Bin 5098 -> 0 bytes .../data/system_addons/system_delay_ignore_2.xpi | Bin 4707 -> 0 bytes .../data/system_addons/system_failed_update.xpi | Bin 735 -> 0 bytes .../test/xpcshell/data/test_AddonRepository.xml | 820 -- .../xpcshell/data/test_AddonRepository_cache.xml | 182 - .../test_AddonRepository_compatmode_ignore.xml | 23 - .../test_AddonRepository_compatmode_normal.xml | 23 - .../test_AddonRepository_compatmode_strict.xml | 23 - .../xpcshell/data/test_AddonRepository_empty.xml | 3 - .../xpcshell/data/test_AddonRepository_failed.xml | 21 - .../data/test_AddonRepository_getAddonsByIDs.xml | 187 - .../test/xpcshell/data/test_backgroundupdate.rdf | 70 - .../data/test_blocklist_metadata_filters_1.xml | 21 - .../test/xpcshell/data/test_blocklist_prefs_1.xml | 28 - .../test/xpcshell/data/test_blocklist_regexp_1.xml | 20 - .../test/xpcshell/data/test_bug299716.rdf | 181 - .../test/xpcshell/data/test_bug299716_2.rdf | 23 - .../test/xpcshell/data/test_bug324121.rdf | 91 - .../test/xpcshell/data/test_bug393285.xml | 30 - .../test/xpcshell/data/test_bug394300.rdf | 159 - .../test/xpcshell/data/test_bug424262.xml | 185 - .../test/xpcshell/data/test_bug449027_app.xml | 333 - .../test/xpcshell/data/test_bug449027_toolkit.xml | 208 - .../test/xpcshell/data/test_bug468528.xml | 15 - .../xpcshell/data/test_bug470377/install_1.rdf | 17 - .../xpcshell/data/test_bug470377/install_2.rdf | 17 - .../xpcshell/data/test_bug470377/install_3.rdf | 17 - .../xpcshell/data/test_bug470377/install_4.rdf | 17 - .../xpcshell/data/test_bug470377/install_5.rdf | 17 - .../test/xpcshell/data/test_bug470377/update_1.rdf | 26 - .../test/xpcshell/data/test_bug470377/update_2.rdf | 26 - .../test/xpcshell/data/test_bug470377/update_3.rdf | 26 - .../test/xpcshell/data/test_bug470377/update_4.rdf | 26 - .../test/xpcshell/data/test_bug470377/update_5.rdf | 26 - .../test/xpcshell/data/test_bug514327_1.xml | 17 - .../test/xpcshell/data/test_bug514327_2.xml | 10 - .../test/xpcshell/data/test_bug514327_3_empty.xml | 4 - .../xpcshell/data/test_bug514327_3_outdated_1.xml | 13 - .../xpcshell/data/test_bug514327_3_outdated_2.xml | 13 - .../test/xpcshell/data/test_bug526598_1.xpi | Bin 458 -> 0 bytes .../test/xpcshell/data/test_bug526598_2.xpi | Bin 458 -> 0 bytes .../test/xpcshell/data/test_bug541420.xpi | Bin 577 -> 0 bytes .../test/xpcshell/data/test_bug542391.rdf | 25 - .../test/xpcshell/data/test_bug554133.xml | 292 - .../test/xpcshell/data/test_bug619730.xml | 7 - .../test/xpcshell/data/test_bug655254.rdf | 26 - .../test/xpcshell/data/test_compatoverrides.xml | 228 - .../extensions/test/xpcshell/data/test_corrupt.rdf | 44 - .../data/test_delay_update_complete/bootstrap.js | 24 - .../data/test_delay_update_defer/bootstrap.js | 34 - .../data/test_delay_update_ignore/bootstrap.js | 26 - .../xpcshell/data/test_delay_updates_complete.json | 11 - .../xpcshell/data/test_delay_updates_complete.rdf | 26 - .../xpcshell/data/test_delay_updates_defer.json | 11 - .../xpcshell/data/test_delay_updates_defer.rdf | 26 - .../xpcshell/data/test_delay_updates_ignore.json | 11 - .../xpcshell/data/test_delay_updates_ignore.rdf | 26 - .../test/xpcshell/data/test_dictionary.rdf | 65 - .../data/test_distribution2_2/bootstrap.js | 21 - .../xpcshell/data/test_distribution2_2/install.rdf | 23 - .../data/test_distribution2_2/subdir/dummy.txt | 1 - .../test_distribution2_2/subdir/subdir2/dummy2.txt | 1 - .../test/xpcshell/data/test_gfxBlacklist.xml | 304 - .../test/xpcshell/data/test_gfxBlacklist2.xml | 31 - .../test/xpcshell/data/test_gfxBlacklist_AllOS.xml | 783 -- .../xpcshell/data/test_gfxBlacklist_OSVersion.xml | 32 - .../test/xpcshell/data/test_hotfix_1.rdf | 26 - .../test/xpcshell/data/test_hotfix_2.rdf | 26 - .../test/xpcshell/data/test_hotfix_3.rdf | 26 - .../extensions/test/xpcshell/data/test_install.rdf | 63 - .../extensions/test/xpcshell/data/test_install.xml | 53 - .../extensions/test/xpcshell/data/test_migrate.rdf | 125 - .../test/xpcshell/data/test_migrate4.rdf | 46 - .../test/xpcshell/data/test_no_update.json | 7 - .../data/test_overrideblocklist/ancient.xml | 8 - .../xpcshell/data/test_overrideblocklist/new.xml | 8 - .../xpcshell/data/test_overrideblocklist/old.xml | 8 - .../test/xpcshell/data/test_pluginBlocklistCtp.xml | 26 - .../xpcshell/data/test_pluginBlocklistCtpUndo.xml | 10 - .../test/xpcshell/data/test_proxy/bootstrap.js | 1 - .../test/xpcshell/data/test_softblocked1.xml | 9 - .../test/xpcshell/data/test_sourceURI.xml | 18 - .../test/xpcshell/data/test_temporary/bootstrap.js | 1 - .../extensions/test/xpcshell/data/test_update.json | 215 - .../extensions/test/xpcshell/data/test_update.rdf | 270 - .../extensions/test/xpcshell/data/test_update.xml | 26 - .../test/xpcshell/data/test_update_multi.rdf | 26 - .../test/xpcshell/data/test_updatecheck.json | 327 - .../test/xpcshell/data/test_updatecheck.rdf | 419 - .../xpcshell/data/test_updatecompatmode_ignore.rdf | 26 - .../xpcshell/data/test_updatecompatmode_normal.rdf | 26 - .../xpcshell/data/test_updatecompatmode_strict.rdf | 26 - .../test/xpcshell/data/test_updateid.rdf | 26 - .../extensions/test/xpcshell/data/unsigned.xpi | Bin 452 -> 0 bytes .../test/xpcshell/data/webext-implicit-id.xpi | Bin 4182 -> 0 bytes .../extensions/test/xpcshell/head_addons.js | 1345 --- .../extensions/test/xpcshell/head_unpack.js | 3 - .../test/xpcshell/test_AddonRepository.js | 625 -- .../test/xpcshell/test_AddonRepository_cache.js | 704 -- .../xpcshell/test_AddonRepository_compatmode.js | 90 - .../test/xpcshell/test_ChromeManifestParser.js | 108 - .../extensions/test/xpcshell/test_DeferredSave.js | 549 -- .../test/xpcshell/test_LightweightThemeManager.js | 598 -- .../test/xpcshell/test_ProductAddonChecker.js | 244 - .../extensions/test/xpcshell/test_XPIStates.js | 299 - .../extensions/test/xpcshell/test_XPIcancel.js | 66 - .../test/xpcshell/test_addon_path_service.js | 38 - .../test/xpcshell/test_asyncBlocklistLoad.js | 44 - .../test/xpcshell/test_backgroundupdate.js | 126 - .../extensions/test/xpcshell/test_bad_json.js | 54 - .../extensions/test/xpcshell/test_badschema.js | 404 - .../extensions/test/xpcshell/test_blocklist_gfx.js | 157 - .../xpcshell/test_blocklist_metadata_filters.js | 147 - .../test/xpcshell/test_blocklist_prefs.js | 148 - .../test/xpcshell/test_blocklist_regexp.js | 114 - .../test/xpcshell/test_blocklistchange.js | 1305 --- .../extensions/test/xpcshell/test_bootstrap.js | 1403 --- .../test/xpcshell/test_bootstrap_const.js | 17 - .../test/xpcshell/test_bootstrap_globals.js | 37 - .../test/xpcshell/test_bootstrap_resource.js | 56 - .../extensions/test/xpcshell/test_bug1180901.js | 35 - .../extensions/test/xpcshell/test_bug1180901_2.js | 60 - .../extensions/test/xpcshell/test_bug299716.js | 208 - .../extensions/test/xpcshell/test_bug299716_2.js | 50 - .../extensions/test/xpcshell/test_bug324121.js | 178 - .../extensions/test/xpcshell/test_bug335238.js | 173 - .../extensions/test/xpcshell/test_bug371495.js | 35 - .../extensions/test/xpcshell/test_bug384052.js | 103 - .../extensions/test/xpcshell/test_bug393285.js | 316 - .../extensions/test/xpcshell/test_bug394300.js | 56 - .../extensions/test/xpcshell/test_bug397778.js | 117 - .../extensions/test/xpcshell/test_bug406118.js | 155 - .../extensions/test/xpcshell/test_bug424262.js | 62 - .../extensions/test/xpcshell/test_bug425657.js | 27 - .../extensions/test/xpcshell/test_bug430120.js | 135 - .../extensions/test/xpcshell/test_bug449027.js | 429 - .../extensions/test/xpcshell/test_bug455906.js | 517 -- .../extensions/test/xpcshell/test_bug465190.js | 39 - .../extensions/test/xpcshell/test_bug468528.js | 58 - .../extensions/test/xpcshell/test_bug470377_1.js | 49 - .../test/xpcshell/test_bug470377_1_strictcompat.js | 49 - .../extensions/test/xpcshell/test_bug470377_2.js | 49 - .../extensions/test/xpcshell/test_bug470377_3.js | 95 - .../test/xpcshell/test_bug470377_3_strictcompat.js | 94 - .../extensions/test/xpcshell/test_bug470377_4.js | 92 - .../extensions/test/xpcshell/test_bug514327_1.js | 59 - .../extensions/test/xpcshell/test_bug514327_2.js | 41 - .../extensions/test/xpcshell/test_bug514327_3.js | 139 - .../extensions/test/xpcshell/test_bug521905.js | 59 - .../extensions/test/xpcshell/test_bug526598.js | 54 - .../extensions/test/xpcshell/test_bug541420.js | 37 - .../extensions/test/xpcshell/test_bug542391.js | 464 - .../extensions/test/xpcshell/test_bug554133.js | 86 - .../extensions/test/xpcshell/test_bug559800.js | 71 - .../extensions/test/xpcshell/test_bug563256.js | 259 - .../extensions/test/xpcshell/test_bug564030.js | 63 - .../extensions/test/xpcshell/test_bug566626.js | 112 - .../extensions/test/xpcshell/test_bug567184.js | 53 - .../extensions/test/xpcshell/test_bug569138.js | 147 - .../extensions/test/xpcshell/test_bug570173.js | 61 - .../extensions/test/xpcshell/test_bug576735.js | 66 - .../extensions/test/xpcshell/test_bug587088.js | 174 - .../extensions/test/xpcshell/test_bug594058.js | 88 - .../extensions/test/xpcshell/test_bug595081.js | 27 - .../extensions/test/xpcshell/test_bug595573.js | 40 - .../extensions/test/xpcshell/test_bug596607.js | 147 - .../extensions/test/xpcshell/test_bug616841.js | 26 - .../extensions/test/xpcshell/test_bug619730.js | 64 - .../extensions/test/xpcshell/test_bug620837.js | 145 - .../extensions/test/xpcshell/test_bug655254.js | 164 - .../extensions/test/xpcshell/test_bug659772.js | 340 - .../extensions/test/xpcshell/test_bug675371.js | 91 - .../extensions/test/xpcshell/test_bug740612.js | 40 - .../extensions/test/xpcshell/test_bug753900.js | 86 - .../extensions/test/xpcshell/test_bug757663.js | 112 - .../extensions/test/xpcshell/test_bug953156.js | 51 - .../extensions/test/xpcshell/test_cache_certdb.js | 82 - .../extensions/test/xpcshell/test_cacheflush.js | 127 - .../test_checkCompatibility_themeOverride.js | 93 - .../test/xpcshell/test_checkcompatibility.js | 196 - .../extensions/test/xpcshell/test_childprocess.js | 21 - .../test/xpcshell/test_compatoverrides.js | 259 - .../extensions/test/xpcshell/test_corrupt.js | 406 - .../test/xpcshell/test_corrupt_strictcompat.js | 405 - .../extensions/test/xpcshell/test_corruptfile.js | 83 - .../extensions/test/xpcshell/test_dataDirectory.js | 50 - .../test/xpcshell/test_default_providers_pref.js | 13 - .../extensions/test/xpcshell/test_delay_update.js | 260 - .../xpcshell/test_delay_update_webextension.js | 344 - .../extensions/test/xpcshell/test_dependencies.js | 144 - .../extensions/test/xpcshell/test_dictionary.js | 811 -- .../extensions/test/xpcshell/test_disable.js | 194 - .../extensions/test/xpcshell/test_distribution.js | 273 - .../mozapps/extensions/test/xpcshell/test_dss.js | 824 -- .../test/xpcshell/test_duplicateplugins.js | 187 - .../test/xpcshell/test_e10s_restartless.js | 429 - .../mozapps/extensions/test/xpcshell/test_error.js | 90 - .../extensions/test/xpcshell/test_experiment.js | 131 - .../test/xpcshell/test_ext_management.js | 137 - .../extensions/test/xpcshell/test_filepointer.js | 403 - .../mozapps/extensions/test/xpcshell/test_fuel.js | 165 - .../extensions/test/xpcshell/test_general.js | 58 - .../extensions/test/xpcshell/test_getresource.js | 94 - .../test/xpcshell/test_gfxBlacklist_Device.js | 96 - .../test/xpcshell/test_gfxBlacklist_DriverNew.js | 92 - .../xpcshell/test_gfxBlacklist_Equal_DriverNew.js | 123 - .../xpcshell/test_gfxBlacklist_Equal_DriverOld.js | 93 - .../test/xpcshell/test_gfxBlacklist_Equal_OK.js | 93 - .../xpcshell/test_gfxBlacklist_GTE_DriverOld.js | 93 - .../test/xpcshell/test_gfxBlacklist_GTE_OK.js | 93 - .../xpcshell/test_gfxBlacklist_No_Comparison.js | 89 - .../test/xpcshell/test_gfxBlacklist_OK.js | 94 - .../test/xpcshell/test_gfxBlacklist_OS.js | 93 - .../xpcshell/test_gfxBlacklist_OSVersion_match.js | 95 - ...fxBlacklist_OSVersion_mismatch_DriverVersion.js | 95 - ...st_gfxBlacklist_OSVersion_mismatch_OSVersion.js | 96 - .../test/xpcshell/test_gfxBlacklist_Vendor.js | 93 - .../test/xpcshell/test_gfxBlacklist_Version.js | 145 - .../test/xpcshell/test_gfxBlacklist_prefs.js | 135 - .../extensions/test/xpcshell/test_gmpProvider.js | 416 - .../test/xpcshell/test_hasbinarycomponents.js | 82 - .../extensions/test/xpcshell/test_hotfix.js | 309 - .../extensions/test/xpcshell/test_hotfix_cert.js | 167 - .../extensions/test/xpcshell/test_install.js | 1843 ---- .../test/xpcshell/test_install_from_sources.js | 80 - .../extensions/test/xpcshell/test_install_icons.js | 61 - .../test/xpcshell/test_install_strictcompat.js | 1726 ---- .../extensions/test/xpcshell/test_isDebuggable.js | 36 - .../extensions/test/xpcshell/test_isReady.js | 49 - .../test/xpcshell/test_json_updatecheck.js | 372 - .../extensions/test/xpcshell/test_langpack.js | 339 - .../extensions/test/xpcshell/test_locale.js | 149 - .../extensions/test/xpcshell/test_locked.js | 544 -- .../extensions/test/xpcshell/test_locked2.js | 297 - .../test/xpcshell/test_locked_strictcompat.js | 567 -- .../extensions/test/xpcshell/test_manifest.js | 562 -- .../test/xpcshell/test_mapURIToAddonID.js | 347 - .../test/xpcshell/test_metadata_update.js | 159 - .../extensions/test/xpcshell/test_migrate1.js | 231 - .../extensions/test/xpcshell/test_migrate2.js | 267 - .../extensions/test/xpcshell/test_migrate3.js | 229 - .../extensions/test/xpcshell/test_migrate4.js | 321 - .../extensions/test/xpcshell/test_migrate5.js | 139 - .../test/xpcshell/test_migrateAddonRepository.js | 127 - .../test/xpcshell/test_migrate_max_version.js | 103 - .../test/xpcshell/test_multiprocessCompatible.js | 120 - .../extensions/test/xpcshell/test_no_addons.js | 98 - .../test/xpcshell/test_nodisable_hidden.js | 107 - .../xpcshell/test_onPropertyChanged_appDisabled.js | 66 - .../test/xpcshell/test_overrideblocklist.js | 200 - .../extensions/test/xpcshell/test_pass_symbol.js | 43 - .../extensions/test/xpcshell/test_permissions.js | 86 - .../test/xpcshell/test_permissions_prefs.js | 74 - .../test/xpcshell/test_pluginBlocklistCtp.js | 182 - .../extensions/test/xpcshell/test_pluginInfoURL.js | 90 - .../extensions/test/xpcshell/test_pluginchange.js | 283 - .../extensions/test/xpcshell/test_plugins.js | 210 - .../test/xpcshell/test_pref_properties.js | 221 - .../test/xpcshell/test_provider_markSafe.js | 49 - .../test/xpcshell/test_provider_shutdown.js | 99 - .../test_provider_unsafe_access_shutdown.js | 64 - .../test_provider_unsafe_access_startup.js | 55 - .../extensions/test/xpcshell/test_proxies.js | 240 - .../mozapps/extensions/test/xpcshell/test_proxy.js | 106 - .../extensions/test/xpcshell/test_registry.js | 158 - .../extensions/test/xpcshell/test_reload.js | 235 - .../extensions/test/xpcshell/test_safemode.js | 115 - .../extensions/test/xpcshell/test_schema_change.js | 317 - .../mozapps/extensions/test/xpcshell/test_seen.js | 211 - .../test/xpcshell/test_seen_newprofile.js | 41 - .../extensions/test/xpcshell/test_shutdown.js | 85 - .../extensions/test/xpcshell/test_signed_inject.js | 382 - .../test/xpcshell/test_signed_install.js | 265 - .../extensions/test/xpcshell/test_signed_long.js | 49 - .../test/xpcshell/test_signed_migrate.js | 194 - .../extensions/test/xpcshell/test_signed_multi.js | 55 - .../test/xpcshell/test_signed_updatepref.js | 136 - .../extensions/test/xpcshell/test_signed_verify.js | 234 - .../extensions/test/xpcshell/test_softblocked.js | 109 - .../extensions/test/xpcshell/test_sourceURI.js | 66 - .../extensions/test/xpcshell/test_startup.js | 932 -- .../test/xpcshell/test_strictcompatibility.js | 203 - .../extensions/test/xpcshell/test_switch_os.js | 52 - .../extensions/test/xpcshell/test_syncGUID.js | 156 - .../test/xpcshell/test_system_delay_update.js | 461 - .../extensions/test/xpcshell/test_system_reset.js | 418 - .../extensions/test/xpcshell/test_system_update.js | 788 -- .../test/xpcshell/test_targetPlatforms.js | 146 - .../extensions/test/xpcshell/test_temporary.js | 760 -- .../mozapps/extensions/test/xpcshell/test_theme.js | 1139 --- .../mozapps/extensions/test/xpcshell/test_types.js | 65 - .../test/xpcshell/test_undothemeuninstall.js | 423 - .../extensions/test/xpcshell/test_undouninstall.js | 792 -- .../extensions/test/xpcshell/test_uninstall.js | 216 - .../extensions/test/xpcshell/test_update.js | 1398 --- .../extensions/test/xpcshell/test_updateCancel.js | 138 - .../test/xpcshell/test_update_compatmode.js | 184 - .../test/xpcshell/test_update_ignorecompat.js | 107 - .../test/xpcshell/test_update_strictcompat.js | 1126 --- .../test/xpcshell/test_update_webextensions.js | 248 - .../extensions/test/xpcshell/test_updatecheck.js | 236 - .../extensions/test/xpcshell/test_updateid.js | 86 - .../extensions/test/xpcshell/test_upgrade.js | 206 - .../test/xpcshell/test_upgrade_strictcompat.js | 209 - .../extensions/test/xpcshell/test_webextension.js | 421 - .../test/xpcshell/test_webextension_embedded.js | 306 - .../test/xpcshell/test_webextension_icons.js | 169 - .../test/xpcshell/test_webextension_install.js | 478 - .../test/xpcshell/test_webextension_paths.js | 55 - .../extensions/test/xpcshell/xpcshell-shared.ini | 334 - .../extensions/test/xpcshell/xpcshell-unpack.ini | 12 - .../mozapps/extensions/test/xpcshell/xpcshell.ini | 50 - .../mozapps/extensions/test/xpinstall/.eslintrc.js | 7 - .../extensions/test/xpinstall/amosigned.xpi | Bin 4420 -> 0 bytes .../extensions/test/xpinstall/amosigned2.xpi | Bin 4421 -> 0 bytes .../extensions/test/xpinstall/authRedirect.sjs | 21 - .../mozapps/extensions/test/xpinstall/browser.ini | 119 - .../test/xpinstall/browser_amosigned_trigger.js | 56 - .../xpinstall/browser_amosigned_trigger_iframe.js | 57 - .../test/xpinstall/browser_amosigned_url.js | 35 - .../extensions/test/xpinstall/browser_auth.js | 47 - .../extensions/test/xpinstall/browser_auth2.js | 46 - .../extensions/test/xpinstall/browser_auth3.js | 53 - .../extensions/test/xpinstall/browser_auth4.js | 52 - .../extensions/test/xpinstall/browser_badargs.js | 38 - .../extensions/test/xpinstall/browser_badargs2.js | 42 - .../extensions/test/xpinstall/browser_badhash.js | 33 - .../test/xpinstall/browser_badhashtype.js | 33 - .../extensions/test/xpinstall/browser_bug540558.js | 25 - .../extensions/test/xpinstall/browser_bug611242.js | 17 - .../extensions/test/xpinstall/browser_bug638292.js | 40 - .../extensions/test/xpinstall/browser_bug645699.js | 36 - .../extensions/test/xpinstall/browser_bug672485.js | 52 - .../extensions/test/xpinstall/browser_cancel.js | 60 - .../test/xpinstall/browser_concurrent_installs.js | 127 - .../extensions/test/xpinstall/browser_cookies.js | 30 - .../extensions/test/xpinstall/browser_cookies2.js | 40 - .../extensions/test/xpinstall/browser_cookies3.js | 44 - .../extensions/test/xpinstall/browser_cookies4.js | 43 - .../extensions/test/xpinstall/browser_corrupt.js | 38 - .../extensions/test/xpinstall/browser_datauri.js | 37 - .../extensions/test/xpinstall/browser_empty.js | 28 - .../extensions/test/xpinstall/browser_enabled.js | 29 - .../extensions/test/xpinstall/browser_enabled2.js | 32 - .../extensions/test/xpinstall/browser_enabled3.js | 52 - .../extensions/test/xpinstall/browser_hash.js | 34 - .../extensions/test/xpinstall/browser_hash2.js | 34 - .../extensions/test/xpinstall/browser_httphash.js | 39 - .../extensions/test/xpinstall/browser_httphash2.js | 39 - .../extensions/test/xpinstall/browser_httphash3.js | 39 - .../extensions/test/xpinstall/browser_httphash4.js | 36 - .../extensions/test/xpinstall/browser_httphash5.js | 40 - .../extensions/test/xpinstall/browser_httphash6.js | 83 - .../test/xpinstall/browser_installchrome.js | 25 - .../extensions/test/xpinstall/browser_localfile.js | 35 - .../test/xpinstall/browser_localfile2.js | 38 - .../test/xpinstall/browser_localfile3.js | 41 - .../test/xpinstall/browser_localfile4.js | 41 - .../test/xpinstall/browser_multipackage.js | 52 - .../test/xpinstall/browser_navigateaway.js | 36 - .../test/xpinstall/browser_navigateaway2.js | 34 - .../test/xpinstall/browser_navigateaway3.js | 38 - .../test/xpinstall/browser_navigateaway4.js | 44 - .../extensions/test/xpinstall/browser_offline.js | 62 - .../extensions/test/xpinstall/browser_relative.js | 55 - .../test/xpinstall/browser_signed_multipackage.js | 53 - .../test/xpinstall/browser_signed_multiple.js | 72 - .../test/xpinstall/browser_signed_naming.js | 67 - .../test/xpinstall/browser_signed_tampered.js | 33 - .../test/xpinstall/browser_signed_trigger.js | 41 - .../test/xpinstall/browser_signed_untrusted.js | 41 - .../test/xpinstall/browser_signed_url.js | 34 - .../test/xpinstall/browser_softwareupdate.js | 25 - .../extensions/test/xpinstall/browser_switchtab.js | 49 - .../test/xpinstall/browser_trigger_redirect.js | 41 - .../test/xpinstall/browser_unsigned_trigger.js | 56 - .../xpinstall/browser_unsigned_trigger_iframe.js | 57 - .../xpinstall/browser_unsigned_trigger_xorigin.js | 38 - .../test/xpinstall/browser_unsigned_url.js | 35 - .../extensions/test/xpinstall/browser_whitelist.js | 53 - .../test/xpinstall/browser_whitelist2.js | 31 - .../test/xpinstall/browser_whitelist3.js | 28 - .../test/xpinstall/browser_whitelist4.js | 30 - .../test/xpinstall/browser_whitelist5.js | 25 - .../test/xpinstall/browser_whitelist6.js | 25 - .../test/xpinstall/browser_whitelist7.js | 32 - .../extensions/test/xpinstall/bug540558.html | 23 - .../extensions/test/xpinstall/bug638292.html | 17 - .../extensions/test/xpinstall/bug645699.html | 31 - .../test/xpinstall/concurrent_installs.html | 40 - .../extensions/test/xpinstall/cookieRedirect.sjs | 24 - .../mozapps/extensions/test/xpinstall/corrupt.xpi | 1 - .../mozapps/extensions/test/xpinstall/empty.xpi | Bin 197 -> 0 bytes .../mozapps/extensions/test/xpinstall/enabled.html | 24 - .../extensions/test/xpinstall/hashRedirect.sjs | 15 - toolkit/mozapps/extensions/test/xpinstall/head.js | 434 - .../extensions/test/xpinstall/incompatible.xpi | Bin 4442 -> 0 bytes .../extensions/test/xpinstall/installchrome.html | 22 - .../extensions/test/xpinstall/installtrigger.html | 44 - .../test/xpinstall/installtrigger_frame.html | 29 - .../extensions/test/xpinstall/multipackage.xpi | Bin 9589 -> 0 bytes .../extensions/test/xpinstall/navigate.html | 26 - .../mozapps/extensions/test/xpinstall/redirect.sjs | 45 - .../test/xpinstall/restartless-unsigned.xpi | Bin 528 -> 0 bytes .../extensions/test/xpinstall/restartless.xpi | Bin 4447 -> 0 bytes .../test/xpinstall/signed-multipackage.xpi | Bin 2976 -> 0 bytes .../extensions/test/xpinstall/signed-no-cn.xpi | Bin 2241 -> 0 bytes .../extensions/test/xpinstall/signed-no-o.xpi | Bin 2247 -> 0 bytes .../extensions/test/xpinstall/signed-tampered.xpi | Bin 2260 -> 0 bytes .../extensions/test/xpinstall/signed-untrusted.xpi | Bin 2237 -> 0 bytes .../mozapps/extensions/test/xpinstall/signed.xpi | Bin 2250 -> 0 bytes .../mozapps/extensions/test/xpinstall/signed2.xpi | Bin 2938 -> 0 bytes .../extensions/test/xpinstall/slowinstall.sjs | 101 - .../test/xpinstall/startsoftwareupdate.html | 20 - .../mozapps/extensions/test/xpinstall/theme.xpi | Bin 4450 -> 0 bytes .../extensions/test/xpinstall/triggerredirect.html | 36 - .../mozapps/extensions/test/xpinstall/unsigned.xpi | Bin 452 -> 0 bytes toolkit/mozapps/webextensions/.eslintrc.js | 8 + .../mozapps/webextensions/AddonContentPolicy.cpp | 478 + toolkit/mozapps/webextensions/AddonContentPolicy.h | 22 + toolkit/mozapps/webextensions/AddonManager.jsm | 3674 ++++++++ .../mozapps/webextensions/AddonManagerWebAPI.cpp | 171 + toolkit/mozapps/webextensions/AddonManagerWebAPI.h | 33 + toolkit/mozapps/webextensions/AddonPathService.cpp | 258 + toolkit/mozapps/webextensions/AddonPathService.h | 55 + .../mozapps/webextensions/ChromeManifestParser.jsm | 157 + toolkit/mozapps/webextensions/DeferredSave.jsm | 275 + .../webextensions/LightweightThemeManager.jsm | 909 ++ toolkit/mozapps/webextensions/addonManager.js | 296 + toolkit/mozapps/webextensions/amContentHandler.js | 100 + toolkit/mozapps/webextensions/amIAddonManager.idl | 29 + .../mozapps/webextensions/amIAddonPathService.idl | 37 + .../webextensions/amIWebInstallListener.idl | 134 + toolkit/mozapps/webextensions/amIWebInstaller.idl | 82 + toolkit/mozapps/webextensions/amInstallTrigger.js | 240 + toolkit/mozapps/webextensions/amWebAPI.js | 269 + .../mozapps/webextensions/amWebInstallListener.js | 348 + .../webextensions/content/OpenH264-license.txt | 59 + toolkit/mozapps/webextensions/content/about.js | 103 + toolkit/mozapps/webextensions/content/about.xul | 57 + .../mozapps/webextensions/content/blocklist.css | 11 + toolkit/mozapps/webextensions/content/blocklist.js | 72 + .../mozapps/webextensions/content/blocklist.xml | 58 + .../mozapps/webextensions/content/blocklist.xul | 46 + toolkit/mozapps/webextensions/content/eula.js | 25 + toolkit/mozapps/webextensions/content/eula.xul | 35 + .../mozapps/webextensions/content/extensions.css | 270 + .../mozapps/webextensions/content/extensions.js | 3915 ++++++++ .../mozapps/webextensions/content/extensions.xml | 2008 +++++ .../mozapps/webextensions/content/extensions.xul | 715 ++ toolkit/mozapps/webextensions/content/gmpPrefs.xul | 8 + toolkit/mozapps/webextensions/content/list.js | 165 + toolkit/mozapps/webextensions/content/list.xul | 44 + toolkit/mozapps/webextensions/content/newaddon.js | 137 + toolkit/mozapps/webextensions/content/newaddon.xul | 67 + .../mozapps/webextensions/content/pluginPrefs.xul | 20 + toolkit/mozapps/webextensions/content/setting.xml | 486 + toolkit/mozapps/webextensions/content/update.js | 663 ++ toolkit/mozapps/webextensions/content/update.xul | 194 + .../mozapps/webextensions/content/updateinfo.xsl | 41 + .../webextensions/content/xpinstallConfirm.css | 8 + .../webextensions/content/xpinstallConfirm.js | 196 + .../webextensions/content/xpinstallConfirm.xul | 37 + .../webextensions/content/xpinstallItem.xml | 51 + .../mozapps/webextensions/docs/SystemAddons.rst | 224 + toolkit/mozapps/webextensions/docs/index.rst | 14 + toolkit/mozapps/webextensions/extensions.manifest | 27 + .../internal/APIExtensionBootstrap.js | 39 + .../webextensions/internal/AddonConstants.jsm | 31 + .../webextensions/internal/AddonLogging.jsm | 192 + .../webextensions/internal/AddonRepository.jsm | 1988 +++++ .../internal/AddonRepository_SQLiteMigrator.jsm | 522 ++ .../webextensions/internal/AddonTestUtils.jsm | 1231 +++ .../webextensions/internal/AddonUpdateChecker.jsm | 934 ++ toolkit/mozapps/webextensions/internal/Content.js | 38 + .../webextensions/internal/E10SAddonsRollout.jsm | 982 +++ .../mozapps/webextensions/internal/GMPProvider.jsm | 699 ++ .../internal/LightweightThemeImageOptimizer.jsm | 180 + .../webextensions/internal/PluginProvider.jsm | 600 ++ .../webextensions/internal/ProductAddonChecker.jsm | 467 + .../internal/SpellCheckDictionaryBootstrap.js | 17 + .../internal/WebExtensionBootstrap.js | 39 + .../mozapps/webextensions/internal/XPIProvider.jsm | 9305 ++++++++++++++++++++ .../webextensions/internal/XPIProviderUtils.js | 2255 +++++ toolkit/mozapps/webextensions/internal/moz.build | 36 + toolkit/mozapps/webextensions/jar.mn | 35 + toolkit/mozapps/webextensions/moz.build | 66 + .../mozapps/webextensions/nsBlocklistService.js | 1667 ++++ .../webextensions/nsBlocklistServiceContent.js | 113 + .../webextensions/test/AddonManagerTesting.jsm | 115 + toolkit/mozapps/webextensions/test/Makefile.in | 20 + .../test/addons/blocklist_hard1_1/install.rdf | 18 + .../test/addons/blocklist_hard1_2/install.rdf | 18 + .../test/addons/blocklist_hard1_3/install.rdf | 18 + .../test/addons/blocklist_regexp1_1/install.rdf | 18 + .../test/addons/blocklist_regexp1_2/install.rdf | 18 + .../test/addons/blocklist_regexp1_3/install.rdf | 18 + .../test/addons/blocklist_soft1_1/install.rdf | 18 + .../test/addons/blocklist_soft1_2/install.rdf | 18 + .../test/addons/blocklist_soft1_3/install.rdf | 18 + .../test/addons/blocklist_soft2_1/install.rdf | 18 + .../test/addons/blocklist_soft2_2/install.rdf | 18 + .../test/addons/blocklist_soft2_3/install.rdf | 18 + .../test/addons/blocklist_soft3_1/install.rdf | 18 + .../test/addons/blocklist_soft3_2/install.rdf | 18 + .../test/addons/blocklist_soft3_3/install.rdf | 18 + .../test/addons/blocklist_soft4_1/install.rdf | 18 + .../test/addons/blocklist_soft4_2/install.rdf | 18 + .../test/addons/blocklist_soft4_3/install.rdf | 18 + .../test/addons/blocklist_soft5_1/install.rdf | 19 + .../test/addons/blocklist_soft5_2/install.rdf | 19 + .../test/addons/blocklist_soft5_3/install.rdf | 19 + .../test/addons/bootstrap_globals/bootstrap.js | 29 + .../test/addons/bootstrap_globals/install.rdf | 23 + .../webextensions/test/addons/min1max1/install.rdf | 22 + .../webextensions/test/addons/min1max2/install.rdf | 22 + .../webextensions/test/addons/min1max3/install.rdf | 22 + .../test/addons/min1max3b/install.rdf | 22 + .../test/addons/override1x2-1x3/install.rdf | 23 + .../test/addons/test_AddonRepository_1/install.rdf | 33 + .../test/addons/test_AddonRepository_2/install.rdf | 23 + .../test/addons/test_AddonRepository_3/icon.png | 1 + .../test/addons/test_AddonRepository_3/install.rdf | 23 + .../test/addons/test_AddonRepository_3/preview.png | 1 + .../test/addons/test_bootstrap1_1/bootstrap.js | 1 + .../test/addons/test_bootstrap1_1/install.rdf | 28 + .../test/addons/test_bootstrap1_1/version.jsm | 3 + .../test/addons/test_bootstrap1_2/bootstrap.js | 1 + .../test/addons/test_bootstrap1_2/install.rdf | 24 + .../test/addons/test_bootstrap1_2/version.jsm | 3 + .../test/addons/test_bootstrap1_3/bootstrap.js | 1 + .../test/addons/test_bootstrap1_3/install.rdf | 24 + .../test/addons/test_bootstrap1_3/version.jsm | 3 + .../test/addons/test_bootstrap1_4/install.rdf | 23 + .../test/addons/test_bootstrap2_1/bootstrap.js | 1 + .../test/addons/test_bootstrap2_1/install.rdf | 28 + .../test/addons/test_bootstrap_const/bootstrap.js | 5 + .../test/addons/test_bootstrap_const/install.rdf | 24 + .../test/addons/test_bug299716_2/install.rdf | 30 + .../test/addons/test_bug299716_a_1/install.rdf | 21 + .../test/addons/test_bug299716_a_2/install.rdf | 21 + .../test/addons/test_bug299716_b_1/install.rdf | 20 + .../test/addons/test_bug299716_b_2/install.rdf | 20 + .../test/addons/test_bug299716_c_1/install.rdf | 30 + .../test/addons/test_bug299716_c_2/install.rdf | 30 + .../test/addons/test_bug299716_d_1/install.rdf | 30 + .../test/addons/test_bug299716_d_2/install.rdf | 30 + .../test/addons/test_bug299716_e_1/install.rdf | 30 + .../test/addons/test_bug299716_e_2/install.rdf | 30 + .../test/addons/test_bug299716_f_1/install.rdf | 30 + .../test/addons/test_bug299716_f_2/install.rdf | 30 + .../test/addons/test_bug299716_g_1/install.rdf | 21 + .../test/addons/test_bug299716_g_2/install.rdf | 21 + .../test/addons/test_bug324121_1/install.rdf | 25 + .../test/addons/test_bug324121_2/install.rdf | 25 + .../test/addons/test_bug324121_3/install.rdf | 25 + .../test/addons/test_bug324121_4/install.rdf | 25 + .../test/addons/test_bug324121_5/install.rdf | 25 + .../test/addons/test_bug324121_6/install.rdf | 25 + .../test/addons/test_bug324121_7/install.rdf | 25 + .../test/addons/test_bug324121_8/install.rdf | 25 + .../test/addons/test_bug324121_9/install.rdf | 25 + .../test/addons/test_bug335238_1/install.rdf | 22 + .../test/addons/test_bug335238_2/install.rdf | 30 + .../test/addons/test_bug335238_3/install.rdf | 30 + .../test/addons/test_bug335238_4/install.rdf | 30 + .../test/addons/test_bug371495/install.rdf | 26 + .../test/addons/test_bug394300_1/install.rdf | 22 + .../test/addons/test_bug394300_2/install.rdf | 22 + .../test/addons/test_bug397778/install.rdf | 78 + .../test/addons/test_bug425657/install.rdf | 17 + .../test/addons/test_bug470377_1/install.rdf | 17 + .../test/addons/test_bug470377_2/install.rdf | 17 + .../test/addons/test_bug470377_3/install.rdf | 17 + .../test/addons/test_bug470377_4/install.rdf | 17 + .../test/addons/test_bug470377_5/install.rdf | 17 + .../test/addons/test_bug521905/install.rdf | 22 + .../test/addons/test_bug567173/install.rdf | 22 + .../test/addons/test_bug567184/bootstrap.js | 7 + .../test/addons/test_bug567184/install.rdf | 24 + .../test/addons/test_bug587088_1/install.rdf | 22 + .../test/addons/test_bug587088_1/testfile | 1 + .../test/addons/test_bug587088_1/testfile1 | 0 .../test/addons/test_bug587088_2/install.rdf | 22 + .../test/addons/test_bug587088_2/testfile | 1 + .../test/addons/test_bug587088_2/testfile2 | 0 .../test/addons/test_bug594058/directory/file1 | 0 .../test/addons/test_bug594058/install.rdf | 21 + .../test/addons/test_bug595573/install.rdf | 24 + .../test/addons/test_bug655254/install.rdf | 18 + .../test/addons/test_bug655254_2/bootstrap.js | 9 + .../test/addons/test_bug655254_2/install.rdf | 19 + .../test/addons/test_bug659772/install.rdf | 24 + .../test/addons/test_bug675371/chrome.manifest | 1 + .../test/addons/test_bug675371/install.rdf | 24 + .../test/addons/test_bug675371/test.js | 1 + .../test/addons/test_bug740612_1/bootstrap.js | 1 + .../test/addons/test_bug740612_1/install.rdf | 24 + .../test/addons/test_bug740612_2/bootstrap.js | 23 + .../test/addons/test_bug740612_2/install.rdf | 24 + .../test/addons/test_bug757663/install.rdf | 24 + .../test/addons/test_cacheflush1/install.rdf | 22 + .../test/addons/test_cacheflush2/install.rdf | 23 + .../addons/test_chromemanifest_1/chrome.manifest | 6 + .../test/addons/test_chromemanifest_1/install.rdf | 23 + .../addons/test_chromemanifest_2/chrome.manifest | 7 + .../test/addons/test_chromemanifest_2/install.rdf | 24 + .../addons/test_chromemanifest_3/chrome.manifest | 9 + .../test/addons/test_chromemanifest_3/inner.jar | Bin 0 -> 180 bytes .../test/addons/test_chromemanifest_3/install.rdf | 24 + .../addons/test_chromemanifest_4/chrome.manifest | 6 + .../components/components.manifest | 2 + .../components/other/something.manifest | 1 + .../test/addons/test_chromemanifest_4/install.rdf | 24 + .../addons/test_chromemanifest_5/chrome.manifest | 7 + .../test/addons/test_chromemanifest_5/install.rdf | 24 + .../addons/test_chromemanifest_6/chrome.manifest | 1 + .../test/addons/test_chromemanifest_6/install.rdf | 24 + .../test/addons/test_data_directory/install.rdf | 22 + .../test/addons/test_db_sanity_1_1/install.rdf | 58 + .../test/addons/test_db_sanity_1_2/install.rdf | 59 + .../test_delay_update_complete_v2/bootstrap.js | 10 + .../test_delay_update_complete_v2/install.rdf | 27 + .../manifest.json | 10 + .../addons/test_delay_update_defer_v2/bootstrap.js | 10 + .../addons/test_delay_update_defer_v2/install.rdf | 27 + .../manifest.json | 10 + .../test_delay_update_ignore_v2/bootstrap.js | 8 + .../addons/test_delay_update_ignore_v2/install.rdf | 28 + .../manifest.json | 10 + .../test/addons/test_dictionary/chrome.manifest | 1 + .../addons/test_dictionary/dictionaries/ab-CD.dic | 2 + .../test/addons/test_dictionary/install.rdf | 25 + .../test_dictionary_2/dictionaries/ab-CD.dic | 2 + .../test/addons/test_dictionary_2/install.rdf | 24 + .../test/addons/test_dictionary_3/install.rdf | 25 + .../test/addons/test_dictionary_4/install.rdf | 24 + .../test/addons/test_dictionary_5/install.rdf | 25 + .../test/addons/test_distribution1_2/install.rdf | 23 + .../test/addons/test_experiment1/bootstrap.js | 1 + .../test/addons/test_experiment1/install.rdf | 16 + .../test/addons/test_filepointer/install.rdf | 22 + .../test/addons/test_getresource/icon.png | 1 + .../test/addons/test_getresource/install.rdf | 23 + .../addons/test_getresource/subdir/subfile.txt | 1 + .../test/addons/test_hotfix_1/install.rdf | 23 + .../test/addons/test_hotfix_2/install.rdf | 23 + .../test/addons/test_install1/icon.png | 1 + .../test/addons/test_install1/icon64.png | 1 + .../test/addons/test_install1/install.rdf | 24 + .../test/addons/test_install2_1/icon.png | 1 + .../test/addons/test_install2_1/install.rdf | 24 + .../test/addons/test_install2_2/install.rdf | 24 + .../test/addons/test_install3/install.rdf | 27 + .../test/addons/test_install4/addon4.xpi | Bin 0 -> 509 bytes .../test/addons/test_install4/addon5.jar | Bin 0 -> 512 bytes .../test/addons/test_install4/addon6.xpi | Bin 0 -> 512 bytes .../test/addons/test_install4/addon7.jar | Bin 0 -> 512 bytes .../test/addons/test_install4/badaddon.jar | 1 + .../test/addons/test_install4/badaddon.xpi | 1 + .../test/addons/test_install4/icon.png | 1 + .../test/addons/test_install4/install.rdf | 10 + .../test/addons/test_install5/chrome.manifest | 1 + .../test/addons/test_install5/install.rdf | 26 + .../test/addons/test_install6/install.rdf | 24 + .../test/addons/test_install7/addon1.xpi | 1 + .../test/addons/test_install7/addon2.xpi | 1 + .../test/addons/test_install7/install.rdf | 10 + .../test/addons/test_install8/install.rdf | 10 + .../test/addons/test_jetpack/bootstrap.js | 17 + .../test/addons/test_jetpack/harness-options.json | 1 + .../test/addons/test_jetpack/install.rdf | 28 + .../test/addons/test_langpack/chrome.manifest | 1 + .../test/addons/test_langpack/install.rdf | 23 + .../test/addons/test_locale/install.rdf | 61 + .../test/addons/test_locked2_5/install.rdf | 23 + .../test/addons/test_locked2_6/install.rdf | 23 + .../test/addons/test_migrate4_6/install.rdf | 23 + .../test/addons/test_migrate4_7/install.rdf | 23 + .../test/addons/test_migrate6/install.rdf | 23 + .../test/addons/test_migrate7/install.rdf | 24 + .../test/addons/test_migrate8/chrome.manifest | 6 + .../test/addons/test_migrate8/install.rdf | 24 + .../test/addons/test_migrate9/install.rdf | 26 + .../test/addons/test_symbol/bootstrap.js | 62 + .../test/addons/test_symbol/install.rdf | 28 + .../test/addons/test_theme/install.rdf | 26 + .../test/addons/test_theme/preview.png | 1 + .../test/addons/test_undoincompatible/bootstrap.js | 1 + .../test/addons/test_undoincompatible/install.rdf | 28 + .../test/addons/test_undouninstall1/bootstrap.js | 1 + .../test/addons/test_undouninstall1/install.rdf | 28 + .../test/addons/test_update/install.rdf | 23 + .../test/addons/test_update12/install.rdf | 23 + .../test/addons/test_update8/install.rdf | 23 + .../test/addons/test_update_multi1/bootstrap.js | 5 + .../test/addons/test_update_multi1/install.rdf | 16 + .../test/addons/test_update_multi2/addon.xpi | Bin 0 -> 693 bytes .../test/addons/test_update_multi2/install.rdf | 9 + .../test/addons/test_updateid1/bootstrap.js | 5 + .../test/addons/test_updateid1/install.rdf | 16 + .../test/addons/test_updateid2/bootstrap.js | 5 + .../test/addons/test_updateid2/install.rdf | 16 + .../test/addons/upgradeable1x2-3_1/install.rdf | 22 + .../test/addons/upgradeable1x2-3_2/install.rdf | 22 + .../test/addons/webextension_1/chrome.manifest | 1 + .../test/addons/webextension_1/manifest.json | 14 + .../test/addons/webextension_2/install.rdf | 30 + .../test/addons/webextension_2/manifest.json | 10 + .../webextension_3/_locales/en/messages.json | 10 + .../webextension_3/_locales/fr/messages.json | 10 + .../test/addons/webextension_3/manifest.json | 12 + .../webextensions/test/browser/.eslintrc.js | 7 + .../webextensions/test/browser/addon_about.xul | 6 + .../webextensions/test/browser/addon_prefs.xul | 6 + .../test/browser/addons/browser_bug557956_1.xpi | Bin 0 -> 4426 bytes .../browser/addons/browser_bug557956_1/install.rdf | 31 + .../test/browser/addons/browser_bug557956_10.xpi | Bin 0 -> 4425 bytes .../addons/browser_bug557956_10/install.rdf | 31 + .../test/browser/addons/browser_bug557956_2.xpi | Bin 0 -> 4427 bytes .../browser/addons/browser_bug557956_2/install.rdf | 31 + .../test/browser/addons/browser_bug557956_3.xpi | Bin 0 -> 4425 bytes .../browser/addons/browser_bug557956_3/install.rdf | 31 + .../test/browser/addons/browser_bug557956_4.xpi | Bin 0 -> 4432 bytes .../browser/addons/browser_bug557956_4/install.rdf | 31 + .../test/browser/addons/browser_bug557956_5.xpi | Bin 0 -> 4427 bytes .../browser/addons/browser_bug557956_5/install.rdf | 31 + .../test/browser/addons/browser_bug557956_6.xpi | Bin 0 -> 4424 bytes .../browser/addons/browser_bug557956_6/install.rdf | 31 + .../test/browser/addons/browser_bug557956_7.xpi | Bin 0 -> 4424 bytes .../browser/addons/browser_bug557956_7/install.rdf | 31 + .../test/browser/addons/browser_bug557956_8_1.xpi | Bin 0 -> 4427 bytes .../addons/browser_bug557956_8_1/install.rdf | 31 + .../test/browser/addons/browser_bug557956_9_1.xpi | Bin 0 -> 4421 bytes .../addons/browser_bug557956_9_1/install.rdf | 31 + .../test/browser/addons/browser_bug567127_1.xpi | Bin 0 -> 4425 bytes .../browser/addons/browser_bug567127_1/install.rdf | 30 + .../test/browser/addons/browser_bug567127_2.xpi | Bin 0 -> 4427 bytes .../browser/addons/browser_bug567127_2/install.rdf | 30 + .../test/browser/addons/browser_bug596336_1.xpi | Bin 0 -> 4449 bytes .../browser/addons/browser_bug596336_1/install.rdf | 31 + .../test/browser/addons/browser_bug596336_2.xpi | Bin 0 -> 4440 bytes .../browser/addons/browser_bug596336_2/install.rdf | 31 + .../test/browser/addons/browser_dragdrop1.xpi | Bin 0 -> 4424 bytes .../browser/addons/browser_dragdrop1/install.rdf | 30 + .../test/browser/addons/browser_dragdrop2.xpi | Bin 0 -> 4420 bytes .../browser/addons/browser_dragdrop2/install.rdf | 30 + .../test/browser/addons/browser_experiment1.xpi | Bin 0 -> 4328 bytes .../browser/addons/browser_experiment1/install.rdf | 16 + .../browser/addons/browser_inlinesettings1.xpi | Bin 0 -> 5811 bytes .../addons/browser_inlinesettings1/bootstrap.js | 8 + .../addons/browser_inlinesettings1/chrome.manifest | 1 + .../addons/browser_inlinesettings1/install.rdf | 27 + .../addons/browser_inlinesettings1/options.xul | 23 + .../addons/browser_inlinesettings1/settings.dtd | 1 + .../addons/browser_inlinesettings1_custom.xpi | Bin 0 -> 6155 bytes .../browser_inlinesettings1_custom/binding.xml | 19 + .../browser_inlinesettings1_custom/bootstrap.js | 8 + .../browser_inlinesettings1_custom/chrome.manifest | 2 + .../browser_inlinesettings1_custom/install.rdf | 27 + .../browser_inlinesettings1_custom/options.xul | 5 + .../browser_inlinesettings1_custom/string.dtd | 1 + .../addons/browser_inlinesettings1_info.xpi | Bin 0 -> 5279 bytes .../browser_inlinesettings1_info/bootstrap.js | 8 + .../browser_inlinesettings1_info/install.rdf | 28 + .../browser_inlinesettings1_info/options.xul | 19 + .../test/browser/addons/browser_install1_1.xpi | Bin 0 -> 4489 bytes .../browser/addons/browser_install1_1/install.rdf | 32 + .../test/browser/addons/browser_install1_2.xpi | Bin 0 -> 4415 bytes .../browser/addons/browser_install1_2/install.rdf | 30 + .../test/browser/addons/browser_installssl.xpi | Bin 0 -> 4430 bytes .../browser/addons/browser_installssl/install.rdf | 30 + .../test/browser/addons/browser_searching.xpi | Bin 0 -> 4808 bytes .../browser/addons/browser_searching/bootstrap.js | 9 + .../browser/addons/browser_searching/install.rdf | 25 + .../test/browser/addons/browser_update1_1.xpi | Bin 0 -> 5479 bytes .../browser/addons/browser_update1_1/bootstrap.js | 12 + .../addons/browser_update1_1/chrome.manifest | 1 + .../addons/browser_update1_1/frame-script.js | 6 + .../browser/addons/browser_update1_1/install.rdf | 31 + .../test/browser/addons/browser_update1_2.xpi | Bin 0 -> 5481 bytes .../browser/addons/browser_update1_2/bootstrap.js | 12 + .../addons/browser_update1_2/chrome.manifest | 1 + .../addons/browser_update1_2/frame-script.js | 6 + .../browser/addons/browser_update1_2/install.rdf | 31 + .../test/browser/addons/browser_webapi_install.xpi | Bin 0 -> 4782 bytes .../addons/browser_webapi_install/bootstrap.js | 9 + .../addons/browser_webapi_install/install.rdf | 29 + .../test/browser/addons/options_signed.xpi | Bin 0 -> 4560 bytes .../browser/addons/options_signed/manifest.json | 11 + .../browser/addons/options_signed/options.html | 9 + .../webextensions/test/browser/blockNoPlugins.xml | 7 + .../webextensions/test/browser/blockPluginHard.xml | 11 + .../webextensions/test/browser/browser-common.ini | 67 + .../webextensions/test/browser/browser-window.ini | 52 + .../mozapps/webextensions/test/browser/browser.ini | 75 + .../test/browser/browser_CTP_plugins.js | 172 + .../webextensions/test/browser/browser_about.js | 84 + .../browser/browser_addonrepository_performance.js | 99 + .../test/browser/browser_bug523784.js | 120 + .../test/browser/browser_bug557943.js | 80 + .../test/browser/browser_bug557956.js | 524 ++ .../test/browser/browser_bug557956.rdf | 310 + .../test/browser/browser_bug557956.xml | 20 + .../test/browser/browser_bug557956_8_2.xpi | Bin 0 -> 4438 bytes .../test/browser/browser_bug557956_9_2.xpi | Bin 0 -> 4426 bytes .../test/browser/browser_bug562797.js | 975 ++ .../test/browser/browser_bug562854.js | 129 + .../test/browser/browser_bug562890.js | 78 + .../test/browser/browser_bug562899.js | 88 + .../test/browser/browser_bug562992.js | 70 + .../test/browser/browser_bug567127.js | 136 + .../test/browser/browser_bug567137.js | 40 + .../test/browser/browser_bug570760.js | 44 + .../test/browser/browser_bug572561.js | 99 + .../test/browser/browser_bug573062.js | 116 + .../test/browser/browser_bug577990.js | 132 + .../test/browser/browser_bug580298.js | 98 + .../test/browser/browser_bug581076.js | 132 + .../test/browser/browser_bug586574.js | 286 + .../test/browser/browser_bug587970.js | 180 + .../test/browser/browser_bug590347.js | 121 + .../test/browser/browser_bug591465.js | 512 ++ .../test/browser/browser_bug591465.xml | 35 + .../test/browser/browser_bug591663.js | 161 + .../test/browser/browser_bug593535.js | 119 + .../test/browser/browser_bug593535.xml | 34 + .../test/browser/browser_bug596336.js | 156 + .../test/browser/browser_bug608316.js | 65 + .../test/browser/browser_bug610764.js | 34 + .../test/browser/browser_bug616841.js | 21 + .../test/browser/browser_bug618502.js | 44 + .../test/browser/browser_bug679604.js | 29 + .../test/browser/browser_bug714593.js | 140 + .../test/browser/browser_cancelCompatCheck.js | 462 + .../browser/browser_checkAddonCompatibility.js | 34 + .../webextensions/test/browser/browser_details.js | 1053 +++ .../test/browser/browser_discovery.js | 651 ++ .../test/browser/browser_discovery_install.js | 133 + .../webextensions/test/browser/browser_dragdrop.js | 234 + .../webextensions/test/browser/browser_eula.js | 85 + .../webextensions/test/browser/browser_eula.xml | 35 + .../test/browser/browser_experiments.js | 654 ++ .../test/browser/browser_globalwarnings.js | 63 + .../test/browser/browser_gmpProvider.js | 418 + .../webextensions/test/browser/browser_hotfix.js | 171 + .../test/browser/browser_inlinesettings.js | 680 ++ .../test/browser/browser_inlinesettings_browser.js | 207 + .../test/browser/browser_inlinesettings_custom.js | 92 + .../test/browser/browser_inlinesettings_info.js | 574 ++ .../webextensions/test/browser/browser_install.js | 312 + .../webextensions/test/browser/browser_install.rdf | 27 + .../test/browser/browser_install.rdf^headers^ | 1 + .../webextensions/test/browser/browser_install.xml | 34 + .../test/browser/browser_install1_3.xpi | Bin 0 -> 4419 bytes .../test/browser/browser_installssl.js | 374 + .../webextensions/test/browser/browser_list.js | 956 ++ .../test/browser/browser_manualupdates.js | 246 + .../test/browser/browser_metadataTimeout.js | 114 + .../webextensions/test/browser/browser_newaddon.js | 232 + .../test/browser/browser_openDialog.js | 173 + .../browser/browser_plugin_enabled_state_locked.js | 124 + .../test/browser/browser_pluginprefs.js | 61 + .../webextensions/test/browser/browser_purchase.js | 197 + .../test/browser/browser_purchase.xml | 180 + .../test/browser/browser_recentupdates.js | 125 + .../test/browser/browser_searching.js | 698 ++ .../test/browser/browser_searching.xml | 277 + .../test/browser/browser_searching_empty.xml | 3 + .../webextensions/test/browser/browser_sorting.js | 372 + .../test/browser/browser_sorting_plugins.js | 95 + .../test/browser/browser_system_addons_are_e10s.js | 13 + .../test/browser/browser_tabsettings.js | 100 + .../test/browser/browser_task_next_test.js | 17 + .../webextensions/test/browser/browser_types.js | 473 + .../test/browser/browser_uninstalling.js | 1098 +++ .../webextensions/test/browser/browser_update.js | 53 + .../webextensions/test/browser/browser_updateid.js | 84 + .../test/browser/browser_updatessl.js | 370 + .../test/browser/browser_updatessl.rdf | 25 + .../test/browser/browser_updatessl.rdf^headers^ | 1 + .../webextensions/test/browser/browser_webapi.js | 106 + .../test/browser/browser_webapi_access.js | 127 + .../test/browser/browser_webapi_addon_listener.js | 174 + .../test/browser/browser_webapi_enable.js | 62 + .../test/browser/browser_webapi_install.js | 311 + .../test/browser/browser_webapi_uninstall.js | 51 + .../test/browser/browser_webext_options.js | 70 + .../test/browser/cancelCompatCheck.sjs | 43 + .../webextensions/test/browser/discovery.html | 10 + .../test/browser/discovery_frame.html | 6 + .../test/browser/discovery_install.html | 19 + toolkit/mozapps/webextensions/test/browser/head.js | 1468 +++ .../webextensions/test/browser/more_options.xul | 32 + .../mozapps/webextensions/test/browser/moz.build | 10 + .../mozapps/webextensions/test/browser/options.xul | 12 + .../webextensions/test/browser/plugin_test.html | 7 + .../webextensions/test/browser/redirect.sjs | 5 + .../webextensions/test/browser/releaseNotes.xhtml | 15 + .../webextensions/test/browser/signed_hotfix.rdf | 26 + .../webextensions/test/browser/signed_hotfix.xpi | Bin 0 -> 2745 bytes .../webextensions/test/browser/unsigned_hotfix.rdf | 26 + .../webextensions/test/browser/unsigned_hotfix.xpi | Bin 0 -> 560 bytes .../test/browser/webapi_addon_listener.html | 30 + .../test/browser/webapi_checkavailable.html | 13 + .../test/browser/webapi_checkchromeframe.xul | 6 + .../test/browser/webapi_checkframed.html | 7 + .../test/browser/webapi_checknavigatedwindow.html | 28 + .../webextensions/test/mochitest/.eslintrc.js | 7 + .../test/mochitest/file_bug687194.xpi | Bin 0 -> 5659 bytes .../webextensions/test/mochitest/file_empty.html | 2 + .../webextensions/test/mochitest/mochitest.ini | 9 + .../test/mochitest/test_bug609794.html | 27 + .../test/mochitest/test_bug687194.html | 133 + .../test/mochitest/test_bug887098.html | 52 + toolkit/mozapps/webextensions/test/moz.build | 19 + .../webextensions/test/xpcshell/.eslintrc.js | 7 + .../test/xpcshell/data/BootstrapMonitor.jsm | 30 + .../xpcshell/data/blocklistchange/addon_change.xml | 31 + .../data/blocklistchange/addon_update1.rdf | 144 + .../data/blocklistchange/addon_update2.rdf | 144 + .../data/blocklistchange/addon_update3.rdf | 144 + .../xpcshell/data/blocklistchange/app_update.xml | 62 + .../data/blocklistchange/blocklist_update1.xml | 3 + .../data/blocklistchange/blocklist_update2.xml | 26 + .../data/blocklistchange/manual_update.xml | 27 + .../test/xpcshell/data/bug455906_block.xml | 18 + .../test/xpcshell/data/bug455906_empty.xml | 7 + .../test/xpcshell/data/bug455906_start.xml | 30 + .../test/xpcshell/data/bug455906_warn.xml | 33 + .../webextensions/test/xpcshell/data/corrupt.xpi | 1 + .../test/xpcshell/data/corruptfile.xpi | Bin 0 -> 633 bytes .../webextensions/test/xpcshell/data/empty.xpi | Bin 0 -> 197 bytes .../test/xpcshell/data/from_sources/bootstrap.js | 1 + .../test/xpcshell/data/from_sources/install.rdf | 28 + .../test/xpcshell/data/pluginInfoURL_block.xml | 45 + .../test/xpcshell/data/productaddons/bad.txt | 1 + .../test/xpcshell/data/productaddons/bad.xml | 3 + .../test/xpcshell/data/productaddons/bad2.xml | 3 + .../test/xpcshell/data/productaddons/empty.xml | 5 + .../test/xpcshell/data/productaddons/good.xml | 11 + .../test/xpcshell/data/productaddons/missing.xml | 3 + .../test/xpcshell/data/productaddons/unsigned.xpi | Bin 0 -> 452 bytes .../data/signing_checks/bootstrap_1/bootstrap.js | 29 + .../data/signing_checks/bootstrap_1/install.rdf | 24 + .../data/signing_checks/bootstrap_1/test.txt | 1 + .../data/signing_checks/bootstrap_2/bootstrap.js | 29 + .../data/signing_checks/bootstrap_2/install.rdf | 24 + .../data/signing_checks/bootstrap_2/test.txt | 1 + .../xpcshell/data/signing_checks/hotfix_badid.xpi | Bin 0 -> 5151 bytes .../xpcshell/data/signing_checks/hotfix_broken.xpi | Bin 0 -> 5298 bytes .../xpcshell/data/signing_checks/hotfix_good.xpi | Bin 0 -> 5158 bytes .../xpcshell/data/signing_checks/long_63_hash.xpi | Bin 0 -> 4471 bytes .../xpcshell/data/signing_checks/long_63_plain.xpi | Bin 0 -> 4433 bytes .../xpcshell/data/signing_checks/long_64_hash.xpi | Bin 0 -> 4474 bytes .../xpcshell/data/signing_checks/long_64_plain.xpi | Bin 0 -> 4436 bytes .../xpcshell/data/signing_checks/long_65_hash.xpi | Bin 0 -> 4487 bytes .../xpcshell/data/signing_checks/multi_badid.xpi | Bin 0 -> 6443 bytes .../xpcshell/data/signing_checks/multi_broken.xpi | Bin 0 -> 6563 bytes .../xpcshell/data/signing_checks/multi_signed.xpi | Bin 0 -> 6425 bytes .../data/signing_checks/multi_unsigned.xpi | Bin 0 -> 2436 bytes .../data/signing_checks/nonbootstrap_1/install.rdf | 23 + .../data/signing_checks/nonbootstrap_1/test.txt | 1 + .../data/signing_checks/nonbootstrap_2/install.rdf | 23 + .../data/signing_checks/nonbootstrap_2/test.txt | 1 + .../signing_checks/preliminary_bootstrap_2.xpi | Bin 0 -> 5161 bytes .../data/signing_checks/signed_bootstrap_1.xpi | Bin 0 -> 5150 bytes .../data/signing_checks/signed_bootstrap_2.xpi | Bin 0 -> 5149 bytes .../signing_checks/signed_bootstrap_badid_2.xpi | Bin 0 -> 5155 bytes .../data/signing_checks/signed_nonbootstrap_2.xpi | Bin 0 -> 4627 bytes .../signing_checks/signed_nonbootstrap_badid_2.xpi | Bin 0 -> 4634 bytes .../data/signing_checks/unsigned_bootstrap_2.xpi | Bin 0 -> 1156 bytes .../signing_checks/unsigned_nonbootstrap_2.xpi | Bin 0 -> 691 bytes .../test/xpcshell/data/system_addons/bootstrap.js | 1 + .../test/xpcshell/data/system_addons/system1_1.xpi | Bin 0 -> 4692 bytes .../data/system_addons/system1_1_badcert.xpi | Bin 0 -> 4808 bytes .../test/xpcshell/data/system_addons/system1_2.xpi | Bin 0 -> 4695 bytes .../test/xpcshell/data/system_addons/system2_1.xpi | Bin 0 -> 4692 bytes .../test/xpcshell/data/system_addons/system2_2.xpi | Bin 0 -> 4695 bytes .../test/xpcshell/data/system_addons/system2_3.xpi | Bin 0 -> 4697 bytes .../test/xpcshell/data/system_addons/system3_1.xpi | Bin 0 -> 4689 bytes .../test/xpcshell/data/system_addons/system3_2.xpi | Bin 0 -> 4691 bytes .../test/xpcshell/data/system_addons/system3_3.xpi | Bin 0 -> 4693 bytes .../test/xpcshell/data/system_addons/system4_1.xpi | Bin 0 -> 4692 bytes .../test/xpcshell/data/system_addons/system5_1.xpi | Bin 0 -> 4691 bytes .../data/system_addons/system6_1_unpack.xpi | Bin 0 -> 4708 bytes .../data/system_addons/system6_2_notBootstrap.xpi | Bin 0 -> 4682 bytes .../system_addons/system6_3_notMultiprocess.xpi | Bin 0 -> 4675 bytes .../data/system_addons/system_delay_complete.xpi | Bin 0 -> 5090 bytes .../data/system_addons/system_delay_complete_2.xpi | Bin 0 -> 4706 bytes .../data/system_addons/system_delay_defer.xpi | Bin 0 -> 5095 bytes .../data/system_addons/system_delay_defer_2.xpi | Bin 0 -> 4701 bytes .../data/system_addons/system_delay_defer_also.xpi | Bin 0 -> 5117 bytes .../system_addons/system_delay_defer_also_2.xpi | Bin 0 -> 4716 bytes .../data/system_addons/system_delay_ignore.xpi | Bin 0 -> 5098 bytes .../data/system_addons/system_delay_ignore_2.xpi | Bin 0 -> 4707 bytes .../data/system_addons/system_failed_update.xpi | Bin 0 -> 735 bytes .../test/xpcshell/data/test_AddonRepository.xml | 820 ++ .../xpcshell/data/test_AddonRepository_cache.xml | 182 + .../test_AddonRepository_compatmode_ignore.xml | 23 + .../test_AddonRepository_compatmode_normal.xml | 23 + .../test_AddonRepository_compatmode_strict.xml | 23 + .../xpcshell/data/test_AddonRepository_empty.xml | 3 + .../xpcshell/data/test_AddonRepository_failed.xml | 21 + .../data/test_AddonRepository_getAddonsByIDs.xml | 187 + .../test/xpcshell/data/test_backgroundupdate.rdf | 70 + .../data/test_blocklist_metadata_filters_1.xml | 21 + .../test/xpcshell/data/test_blocklist_prefs_1.xml | 28 + .../test/xpcshell/data/test_blocklist_regexp_1.xml | 20 + .../test/xpcshell/data/test_bug299716.rdf | 181 + .../test/xpcshell/data/test_bug299716_2.rdf | 23 + .../test/xpcshell/data/test_bug324121.rdf | 91 + .../test/xpcshell/data/test_bug393285.xml | 30 + .../test/xpcshell/data/test_bug394300.rdf | 159 + .../test/xpcshell/data/test_bug424262.xml | 185 + .../test/xpcshell/data/test_bug449027_app.xml | 333 + .../test/xpcshell/data/test_bug449027_toolkit.xml | 208 + .../test/xpcshell/data/test_bug468528.xml | 15 + .../xpcshell/data/test_bug470377/install_1.rdf | 17 + .../xpcshell/data/test_bug470377/install_2.rdf | 17 + .../xpcshell/data/test_bug470377/install_3.rdf | 17 + .../xpcshell/data/test_bug470377/install_4.rdf | 17 + .../xpcshell/data/test_bug470377/install_5.rdf | 17 + .../test/xpcshell/data/test_bug470377/update_1.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_2.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_3.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_4.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_5.rdf | 26 + .../test/xpcshell/data/test_bug514327_1.xml | 17 + .../test/xpcshell/data/test_bug514327_2.xml | 10 + .../test/xpcshell/data/test_bug514327_3_empty.xml | 4 + .../xpcshell/data/test_bug514327_3_outdated_1.xml | 13 + .../xpcshell/data/test_bug514327_3_outdated_2.xml | 13 + .../test/xpcshell/data/test_bug526598_1.xpi | Bin 0 -> 458 bytes .../test/xpcshell/data/test_bug526598_2.xpi | Bin 0 -> 458 bytes .../test/xpcshell/data/test_bug541420.xpi | Bin 0 -> 577 bytes .../test/xpcshell/data/test_bug542391.rdf | 25 + .../test/xpcshell/data/test_bug554133.xml | 292 + .../test/xpcshell/data/test_bug619730.xml | 7 + .../test/xpcshell/data/test_bug655254.rdf | 26 + .../test/xpcshell/data/test_compatoverrides.xml | 228 + .../test/xpcshell/data/test_corrupt.rdf | 44 + .../data/test_delay_update_complete/bootstrap.js | 24 + .../data/test_delay_update_defer/bootstrap.js | 34 + .../data/test_delay_update_ignore/bootstrap.js | 26 + .../xpcshell/data/test_delay_updates_complete.json | 11 + .../xpcshell/data/test_delay_updates_complete.rdf | 26 + .../xpcshell/data/test_delay_updates_defer.json | 11 + .../xpcshell/data/test_delay_updates_defer.rdf | 26 + .../xpcshell/data/test_delay_updates_ignore.json | 11 + .../xpcshell/data/test_delay_updates_ignore.rdf | 26 + .../test/xpcshell/data/test_dictionary.rdf | 65 + .../data/test_distribution2_2/bootstrap.js | 21 + .../xpcshell/data/test_distribution2_2/install.rdf | 23 + .../data/test_distribution2_2/subdir/dummy.txt | 1 + .../test_distribution2_2/subdir/subdir2/dummy2.txt | 1 + .../test/xpcshell/data/test_gfxBlacklist.xml | 304 + .../test/xpcshell/data/test_gfxBlacklist2.xml | 31 + .../test/xpcshell/data/test_gfxBlacklist_AllOS.xml | 783 ++ .../xpcshell/data/test_gfxBlacklist_OSVersion.xml | 32 + .../test/xpcshell/data/test_hotfix_1.rdf | 26 + .../test/xpcshell/data/test_hotfix_2.rdf | 26 + .../test/xpcshell/data/test_hotfix_3.rdf | 26 + .../test/xpcshell/data/test_install.rdf | 63 + .../test/xpcshell/data/test_install.xml | 53 + .../test/xpcshell/data/test_migrate.rdf | 125 + .../test/xpcshell/data/test_migrate4.rdf | 46 + .../test/xpcshell/data/test_no_update.json | 7 + .../data/test_overrideblocklist/ancient.xml | 8 + .../xpcshell/data/test_overrideblocklist/new.xml | 8 + .../xpcshell/data/test_overrideblocklist/old.xml | 8 + .../test/xpcshell/data/test_pluginBlocklistCtp.xml | 26 + .../xpcshell/data/test_pluginBlocklistCtpUndo.xml | 10 + .../test/xpcshell/data/test_proxy/bootstrap.js | 1 + .../test/xpcshell/data/test_softblocked1.xml | 9 + .../test/xpcshell/data/test_sourceURI.xml | 18 + .../test/xpcshell/data/test_temporary/bootstrap.js | 1 + .../test/xpcshell/data/test_update.json | 215 + .../test/xpcshell/data/test_update.rdf | 270 + .../test/xpcshell/data/test_update.xml | 26 + .../test/xpcshell/data/test_update_multi.rdf | 26 + .../test/xpcshell/data/test_updatecheck.json | 327 + .../test/xpcshell/data/test_updatecheck.rdf | 419 + .../xpcshell/data/test_updatecompatmode_ignore.rdf | 26 + .../xpcshell/data/test_updatecompatmode_normal.rdf | 26 + .../xpcshell/data/test_updatecompatmode_strict.rdf | 26 + .../test/xpcshell/data/test_updateid.rdf | 26 + .../webextensions/test/xpcshell/data/unsigned.xpi | Bin 0 -> 452 bytes .../test/xpcshell/data/webext-implicit-id.xpi | Bin 0 -> 4182 bytes .../webextensions/test/xpcshell/head_addons.js | 1345 +++ .../webextensions/test/xpcshell/head_unpack.js | 3 + .../test/xpcshell/test_AddonRepository.js | 625 ++ .../test/xpcshell/test_AddonRepository_cache.js | 704 ++ .../xpcshell/test_AddonRepository_compatmode.js | 90 + .../test/xpcshell/test_ChromeManifestParser.js | 108 + .../test/xpcshell/test_DeferredSave.js | 549 ++ .../test/xpcshell/test_LightweightThemeManager.js | 598 ++ .../test/xpcshell/test_ProductAddonChecker.js | 244 + .../webextensions/test/xpcshell/test_XPIStates.js | 299 + .../webextensions/test/xpcshell/test_XPIcancel.js | 66 + .../test/xpcshell/test_addon_path_service.js | 38 + .../test/xpcshell/test_asyncBlocklistLoad.js | 44 + .../test/xpcshell/test_backgroundupdate.js | 126 + .../webextensions/test/xpcshell/test_bad_json.js | 54 + .../webextensions/test/xpcshell/test_badschema.js | 404 + .../test/xpcshell/test_blocklist_gfx.js | 157 + .../xpcshell/test_blocklist_metadata_filters.js | 147 + .../test/xpcshell/test_blocklist_prefs.js | 148 + .../test/xpcshell/test_blocklist_regexp.js | 114 + .../test/xpcshell/test_blocklistchange.js | 1305 +++ .../webextensions/test/xpcshell/test_bootstrap.js | 1403 +++ .../test/xpcshell/test_bootstrap_const.js | 17 + .../test/xpcshell/test_bootstrap_globals.js | 37 + .../test/xpcshell/test_bootstrap_resource.js | 56 + .../webextensions/test/xpcshell/test_bug1180901.js | 35 + .../test/xpcshell/test_bug1180901_2.js | 60 + .../webextensions/test/xpcshell/test_bug299716.js | 208 + .../test/xpcshell/test_bug299716_2.js | 50 + .../webextensions/test/xpcshell/test_bug324121.js | 178 + .../webextensions/test/xpcshell/test_bug335238.js | 173 + .../webextensions/test/xpcshell/test_bug371495.js | 35 + .../webextensions/test/xpcshell/test_bug384052.js | 103 + .../webextensions/test/xpcshell/test_bug393285.js | 316 + .../webextensions/test/xpcshell/test_bug394300.js | 56 + .../webextensions/test/xpcshell/test_bug397778.js | 117 + .../webextensions/test/xpcshell/test_bug406118.js | 155 + .../webextensions/test/xpcshell/test_bug424262.js | 62 + .../webextensions/test/xpcshell/test_bug425657.js | 27 + .../webextensions/test/xpcshell/test_bug430120.js | 135 + .../webextensions/test/xpcshell/test_bug449027.js | 429 + .../webextensions/test/xpcshell/test_bug455906.js | 517 ++ .../webextensions/test/xpcshell/test_bug465190.js | 39 + .../webextensions/test/xpcshell/test_bug468528.js | 58 + .../test/xpcshell/test_bug470377_1.js | 49 + .../test/xpcshell/test_bug470377_1_strictcompat.js | 49 + .../test/xpcshell/test_bug470377_2.js | 49 + .../test/xpcshell/test_bug470377_3.js | 95 + .../test/xpcshell/test_bug470377_3_strictcompat.js | 94 + .../test/xpcshell/test_bug470377_4.js | 92 + .../test/xpcshell/test_bug514327_1.js | 59 + .../test/xpcshell/test_bug514327_2.js | 41 + .../test/xpcshell/test_bug514327_3.js | 139 + .../webextensions/test/xpcshell/test_bug521905.js | 59 + .../webextensions/test/xpcshell/test_bug526598.js | 54 + .../webextensions/test/xpcshell/test_bug541420.js | 37 + .../webextensions/test/xpcshell/test_bug542391.js | 464 + .../webextensions/test/xpcshell/test_bug554133.js | 86 + .../webextensions/test/xpcshell/test_bug559800.js | 71 + .../webextensions/test/xpcshell/test_bug563256.js | 259 + .../webextensions/test/xpcshell/test_bug564030.js | 63 + .../webextensions/test/xpcshell/test_bug566626.js | 112 + .../webextensions/test/xpcshell/test_bug567184.js | 53 + .../webextensions/test/xpcshell/test_bug569138.js | 147 + .../webextensions/test/xpcshell/test_bug570173.js | 61 + .../webextensions/test/xpcshell/test_bug576735.js | 66 + .../webextensions/test/xpcshell/test_bug587088.js | 174 + .../webextensions/test/xpcshell/test_bug594058.js | 88 + .../webextensions/test/xpcshell/test_bug595081.js | 27 + .../webextensions/test/xpcshell/test_bug595573.js | 40 + .../webextensions/test/xpcshell/test_bug596607.js | 147 + .../webextensions/test/xpcshell/test_bug616841.js | 26 + .../webextensions/test/xpcshell/test_bug619730.js | 64 + .../webextensions/test/xpcshell/test_bug620837.js | 145 + .../webextensions/test/xpcshell/test_bug655254.js | 164 + .../webextensions/test/xpcshell/test_bug659772.js | 340 + .../webextensions/test/xpcshell/test_bug675371.js | 91 + .../webextensions/test/xpcshell/test_bug740612.js | 40 + .../webextensions/test/xpcshell/test_bug753900.js | 86 + .../webextensions/test/xpcshell/test_bug757663.js | 112 + .../webextensions/test/xpcshell/test_bug953156.js | 51 + .../test/xpcshell/test_cache_certdb.js | 82 + .../webextensions/test/xpcshell/test_cacheflush.js | 127 + .../test_checkCompatibility_themeOverride.js | 93 + .../test/xpcshell/test_checkcompatibility.js | 196 + .../test/xpcshell/test_childprocess.js | 21 + .../test/xpcshell/test_compatoverrides.js | 259 + .../webextensions/test/xpcshell/test_corrupt.js | 406 + .../test/xpcshell/test_corrupt_strictcompat.js | 405 + .../test/xpcshell/test_corruptfile.js | 83 + .../test/xpcshell/test_dataDirectory.js | 50 + .../test/xpcshell/test_default_providers_pref.js | 13 + .../test/xpcshell/test_delay_update.js | 260 + .../xpcshell/test_delay_update_webextension.js | 344 + .../test/xpcshell/test_dependencies.js | 144 + .../webextensions/test/xpcshell/test_dictionary.js | 811 ++ .../webextensions/test/xpcshell/test_disable.js | 194 + .../test/xpcshell/test_distribution.js | 273 + .../webextensions/test/xpcshell/test_dss.js | 824 ++ .../test/xpcshell/test_duplicateplugins.js | 187 + .../test/xpcshell/test_e10s_restartless.js | 429 + .../webextensions/test/xpcshell/test_error.js | 90 + .../webextensions/test/xpcshell/test_experiment.js | 131 + .../test/xpcshell/test_ext_management.js | 137 + .../test/xpcshell/test_filepointer.js | 403 + .../webextensions/test/xpcshell/test_fuel.js | 165 + .../webextensions/test/xpcshell/test_general.js | 58 + .../test/xpcshell/test_getresource.js | 94 + .../test/xpcshell/test_gfxBlacklist_Device.js | 96 + .../test/xpcshell/test_gfxBlacklist_DriverNew.js | 92 + .../xpcshell/test_gfxBlacklist_Equal_DriverNew.js | 123 + .../xpcshell/test_gfxBlacklist_Equal_DriverOld.js | 93 + .../test/xpcshell/test_gfxBlacklist_Equal_OK.js | 93 + .../xpcshell/test_gfxBlacklist_GTE_DriverOld.js | 93 + .../test/xpcshell/test_gfxBlacklist_GTE_OK.js | 93 + .../xpcshell/test_gfxBlacklist_No_Comparison.js | 89 + .../test/xpcshell/test_gfxBlacklist_OK.js | 94 + .../test/xpcshell/test_gfxBlacklist_OS.js | 93 + .../xpcshell/test_gfxBlacklist_OSVersion_match.js | 95 + ...fxBlacklist_OSVersion_mismatch_DriverVersion.js | 95 + ...st_gfxBlacklist_OSVersion_mismatch_OSVersion.js | 96 + .../test/xpcshell/test_gfxBlacklist_Vendor.js | 93 + .../test/xpcshell/test_gfxBlacklist_Version.js | 145 + .../test/xpcshell/test_gfxBlacklist_prefs.js | 135 + .../test/xpcshell/test_gmpProvider.js | 416 + .../test/xpcshell/test_hasbinarycomponents.js | 82 + .../webextensions/test/xpcshell/test_hotfix.js | 309 + .../test/xpcshell/test_hotfix_cert.js | 167 + .../webextensions/test/xpcshell/test_install.js | 1843 ++++ .../test/xpcshell/test_install_from_sources.js | 80 + .../test/xpcshell/test_install_icons.js | 61 + .../test/xpcshell/test_install_strictcompat.js | 1726 ++++ .../test/xpcshell/test_isDebuggable.js | 36 + .../webextensions/test/xpcshell/test_isReady.js | 49 + .../test/xpcshell/test_json_updatecheck.js | 372 + .../webextensions/test/xpcshell/test_langpack.js | 339 + .../webextensions/test/xpcshell/test_locale.js | 149 + .../webextensions/test/xpcshell/test_locked.js | 544 ++ .../webextensions/test/xpcshell/test_locked2.js | 297 + .../test/xpcshell/test_locked_strictcompat.js | 567 ++ .../webextensions/test/xpcshell/test_manifest.js | 562 ++ .../test/xpcshell/test_mapURIToAddonID.js | 347 + .../test/xpcshell/test_metadata_update.js | 159 + .../webextensions/test/xpcshell/test_migrate1.js | 231 + .../webextensions/test/xpcshell/test_migrate2.js | 267 + .../webextensions/test/xpcshell/test_migrate3.js | 229 + .../webextensions/test/xpcshell/test_migrate4.js | 321 + .../webextensions/test/xpcshell/test_migrate5.js | 139 + .../test/xpcshell/test_migrateAddonRepository.js | 127 + .../test/xpcshell/test_migrate_max_version.js | 103 + .../test/xpcshell/test_multiprocessCompatible.js | 120 + .../webextensions/test/xpcshell/test_no_addons.js | 98 + .../test/xpcshell/test_nodisable_hidden.js | 107 + .../xpcshell/test_onPropertyChanged_appDisabled.js | 66 + .../test/xpcshell/test_overrideblocklist.js | 200 + .../test/xpcshell/test_pass_symbol.js | 43 + .../test/xpcshell/test_permissions.js | 86 + .../test/xpcshell/test_permissions_prefs.js | 74 + .../test/xpcshell/test_pluginBlocklistCtp.js | 182 + .../test/xpcshell/test_pluginInfoURL.js | 90 + .../test/xpcshell/test_pluginchange.js | 283 + .../webextensions/test/xpcshell/test_plugins.js | 210 + .../test/xpcshell/test_pref_properties.js | 221 + .../test/xpcshell/test_provider_markSafe.js | 49 + .../test/xpcshell/test_provider_shutdown.js | 99 + .../test_provider_unsafe_access_shutdown.js | 64 + .../test_provider_unsafe_access_startup.js | 55 + .../webextensions/test/xpcshell/test_proxies.js | 240 + .../webextensions/test/xpcshell/test_proxy.js | 106 + .../webextensions/test/xpcshell/test_registry.js | 158 + .../webextensions/test/xpcshell/test_reload.js | 235 + .../webextensions/test/xpcshell/test_safemode.js | 115 + .../test/xpcshell/test_schema_change.js | 317 + .../webextensions/test/xpcshell/test_seen.js | 211 + .../test/xpcshell/test_seen_newprofile.js | 41 + .../webextensions/test/xpcshell/test_shutdown.js | 85 + .../test/xpcshell/test_signed_inject.js | 382 + .../test/xpcshell/test_signed_install.js | 265 + .../test/xpcshell/test_signed_long.js | 49 + .../test/xpcshell/test_signed_migrate.js | 194 + .../test/xpcshell/test_signed_multi.js | 55 + .../test/xpcshell/test_signed_updatepref.js | 136 + .../test/xpcshell/test_signed_verify.js | 234 + .../test/xpcshell/test_softblocked.js | 109 + .../webextensions/test/xpcshell/test_sourceURI.js | 66 + .../webextensions/test/xpcshell/test_startup.js | 932 ++ .../test/xpcshell/test_strictcompatibility.js | 203 + .../webextensions/test/xpcshell/test_switch_os.js | 52 + .../webextensions/test/xpcshell/test_syncGUID.js | 156 + .../test/xpcshell/test_system_delay_update.js | 461 + .../test/xpcshell/test_system_reset.js | 418 + .../test/xpcshell/test_system_update.js | 788 ++ .../test/xpcshell/test_targetPlatforms.js | 146 + .../webextensions/test/xpcshell/test_temporary.js | 760 ++ .../webextensions/test/xpcshell/test_theme.js | 1139 +++ .../webextensions/test/xpcshell/test_types.js | 65 + .../test/xpcshell/test_undothemeuninstall.js | 423 + .../test/xpcshell/test_undouninstall.js | 792 ++ .../webextensions/test/xpcshell/test_uninstall.js | 216 + .../webextensions/test/xpcshell/test_update.js | 1398 +++ .../test/xpcshell/test_updateCancel.js | 138 + .../test/xpcshell/test_update_compatmode.js | 184 + .../test/xpcshell/test_update_ignorecompat.js | 107 + .../test/xpcshell/test_update_strictcompat.js | 1126 +++ .../test/xpcshell/test_update_webextensions.js | 248 + .../test/xpcshell/test_updatecheck.js | 236 + .../webextensions/test/xpcshell/test_updateid.js | 86 + .../webextensions/test/xpcshell/test_upgrade.js | 206 + .../test/xpcshell/test_upgrade_strictcompat.js | 209 + .../test/xpcshell/test_webextension.js | 421 + .../test/xpcshell/test_webextension_embedded.js | 306 + .../test/xpcshell/test_webextension_icons.js | 169 + .../test/xpcshell/test_webextension_install.js | 478 + .../test/xpcshell/test_webextension_paths.js | 55 + .../test/xpcshell/xpcshell-shared.ini | 334 + .../test/xpcshell/xpcshell-unpack.ini | 12 + .../webextensions/test/xpcshell/xpcshell.ini | 50 + .../webextensions/test/xpinstall/.eslintrc.js | 7 + .../webextensions/test/xpinstall/amosigned.xpi | Bin 0 -> 4420 bytes .../webextensions/test/xpinstall/amosigned2.xpi | Bin 0 -> 4421 bytes .../webextensions/test/xpinstall/authRedirect.sjs | 21 + .../webextensions/test/xpinstall/browser.ini | 119 + .../test/xpinstall/browser_amosigned_trigger.js | 56 + .../xpinstall/browser_amosigned_trigger_iframe.js | 57 + .../test/xpinstall/browser_amosigned_url.js | 35 + .../webextensions/test/xpinstall/browser_auth.js | 47 + .../webextensions/test/xpinstall/browser_auth2.js | 46 + .../webextensions/test/xpinstall/browser_auth3.js | 53 + .../webextensions/test/xpinstall/browser_auth4.js | 52 + .../test/xpinstall/browser_badargs.js | 38 + .../test/xpinstall/browser_badargs2.js | 42 + .../test/xpinstall/browser_badhash.js | 33 + .../test/xpinstall/browser_badhashtype.js | 33 + .../test/xpinstall/browser_bug540558.js | 25 + .../test/xpinstall/browser_bug611242.js | 17 + .../test/xpinstall/browser_bug638292.js | 40 + .../test/xpinstall/browser_bug645699.js | 36 + .../test/xpinstall/browser_bug672485.js | 52 + .../webextensions/test/xpinstall/browser_cancel.js | 60 + .../test/xpinstall/browser_concurrent_installs.js | 127 + .../test/xpinstall/browser_cookies.js | 30 + .../test/xpinstall/browser_cookies2.js | 40 + .../test/xpinstall/browser_cookies3.js | 44 + .../test/xpinstall/browser_cookies4.js | 43 + .../test/xpinstall/browser_corrupt.js | 38 + .../test/xpinstall/browser_datauri.js | 37 + .../webextensions/test/xpinstall/browser_empty.js | 28 + .../test/xpinstall/browser_enabled.js | 29 + .../test/xpinstall/browser_enabled2.js | 32 + .../test/xpinstall/browser_enabled3.js | 52 + .../webextensions/test/xpinstall/browser_hash.js | 34 + .../webextensions/test/xpinstall/browser_hash2.js | 34 + .../test/xpinstall/browser_httphash.js | 39 + .../test/xpinstall/browser_httphash2.js | 39 + .../test/xpinstall/browser_httphash3.js | 39 + .../test/xpinstall/browser_httphash4.js | 36 + .../test/xpinstall/browser_httphash5.js | 40 + .../test/xpinstall/browser_httphash6.js | 83 + .../test/xpinstall/browser_installchrome.js | 25 + .../test/xpinstall/browser_localfile.js | 35 + .../test/xpinstall/browser_localfile2.js | 38 + .../test/xpinstall/browser_localfile3.js | 41 + .../test/xpinstall/browser_localfile4.js | 41 + .../test/xpinstall/browser_multipackage.js | 52 + .../test/xpinstall/browser_navigateaway.js | 36 + .../test/xpinstall/browser_navigateaway2.js | 34 + .../test/xpinstall/browser_navigateaway3.js | 38 + .../test/xpinstall/browser_navigateaway4.js | 44 + .../test/xpinstall/browser_offline.js | 62 + .../test/xpinstall/browser_relative.js | 55 + .../test/xpinstall/browser_signed_multipackage.js | 53 + .../test/xpinstall/browser_signed_multiple.js | 72 + .../test/xpinstall/browser_signed_naming.js | 67 + .../test/xpinstall/browser_signed_tampered.js | 33 + .../test/xpinstall/browser_signed_trigger.js | 41 + .../test/xpinstall/browser_signed_untrusted.js | 41 + .../test/xpinstall/browser_signed_url.js | 34 + .../test/xpinstall/browser_softwareupdate.js | 25 + .../test/xpinstall/browser_switchtab.js | 49 + .../test/xpinstall/browser_trigger_redirect.js | 41 + .../test/xpinstall/browser_unsigned_trigger.js | 56 + .../xpinstall/browser_unsigned_trigger_iframe.js | 57 + .../xpinstall/browser_unsigned_trigger_xorigin.js | 38 + .../test/xpinstall/browser_unsigned_url.js | 35 + .../test/xpinstall/browser_whitelist.js | 53 + .../test/xpinstall/browser_whitelist2.js | 31 + .../test/xpinstall/browser_whitelist3.js | 28 + .../test/xpinstall/browser_whitelist4.js | 30 + .../test/xpinstall/browser_whitelist5.js | 25 + .../test/xpinstall/browser_whitelist6.js | 25 + .../test/xpinstall/browser_whitelist7.js | 32 + .../webextensions/test/xpinstall/bug540558.html | 23 + .../webextensions/test/xpinstall/bug638292.html | 17 + .../webextensions/test/xpinstall/bug645699.html | 31 + .../test/xpinstall/concurrent_installs.html | 40 + .../test/xpinstall/cookieRedirect.sjs | 24 + .../webextensions/test/xpinstall/corrupt.xpi | 1 + .../mozapps/webextensions/test/xpinstall/empty.xpi | Bin 0 -> 197 bytes .../webextensions/test/xpinstall/enabled.html | 24 + .../webextensions/test/xpinstall/hashRedirect.sjs | 15 + .../mozapps/webextensions/test/xpinstall/head.js | 434 + .../webextensions/test/xpinstall/incompatible.xpi | Bin 0 -> 4442 bytes .../test/xpinstall/installchrome.html | 22 + .../test/xpinstall/installtrigger.html | 44 + .../test/xpinstall/installtrigger_frame.html | 29 + .../webextensions/test/xpinstall/multipackage.xpi | Bin 0 -> 9589 bytes .../webextensions/test/xpinstall/navigate.html | 26 + .../webextensions/test/xpinstall/redirect.sjs | 45 + .../test/xpinstall/restartless-unsigned.xpi | Bin 0 -> 528 bytes .../webextensions/test/xpinstall/restartless.xpi | Bin 0 -> 4447 bytes .../test/xpinstall/signed-multipackage.xpi | Bin 0 -> 2976 bytes .../webextensions/test/xpinstall/signed-no-cn.xpi | Bin 0 -> 2241 bytes .../webextensions/test/xpinstall/signed-no-o.xpi | Bin 0 -> 2247 bytes .../test/xpinstall/signed-tampered.xpi | Bin 0 -> 2260 bytes .../test/xpinstall/signed-untrusted.xpi | Bin 0 -> 2237 bytes .../webextensions/test/xpinstall/signed.xpi | Bin 0 -> 2250 bytes .../webextensions/test/xpinstall/signed2.xpi | Bin 0 -> 2938 bytes .../webextensions/test/xpinstall/slowinstall.sjs | 101 + .../test/xpinstall/startsoftwareupdate.html | 20 + .../mozapps/webextensions/test/xpinstall/theme.xpi | Bin 0 -> 4450 bytes .../test/xpinstall/triggerredirect.html | 36 + .../webextensions/test/xpinstall/unsigned.xpi | Bin 0 -> 452 bytes 1988 files changed, 126566 insertions(+), 126566 deletions(-) delete mode 100644 toolkit/mozapps/extensions/.eslintrc.js delete mode 100644 toolkit/mozapps/extensions/AddonContentPolicy.cpp delete mode 100644 toolkit/mozapps/extensions/AddonContentPolicy.h delete mode 100644 toolkit/mozapps/extensions/AddonManager.jsm delete mode 100644 toolkit/mozapps/extensions/AddonManagerWebAPI.cpp delete mode 100644 toolkit/mozapps/extensions/AddonManagerWebAPI.h delete mode 100644 toolkit/mozapps/extensions/AddonPathService.cpp delete mode 100644 toolkit/mozapps/extensions/AddonPathService.h delete mode 100644 toolkit/mozapps/extensions/ChromeManifestParser.jsm delete mode 100644 toolkit/mozapps/extensions/DeferredSave.jsm delete mode 100644 toolkit/mozapps/extensions/LightweightThemeManager.jsm delete mode 100644 toolkit/mozapps/extensions/addonManager.js delete mode 100644 toolkit/mozapps/extensions/amContentHandler.js delete mode 100644 toolkit/mozapps/extensions/amIAddonManager.idl delete mode 100644 toolkit/mozapps/extensions/amIAddonPathService.idl delete mode 100644 toolkit/mozapps/extensions/amIWebInstallListener.idl delete mode 100644 toolkit/mozapps/extensions/amIWebInstaller.idl delete mode 100644 toolkit/mozapps/extensions/amInstallTrigger.js delete mode 100644 toolkit/mozapps/extensions/amWebAPI.js delete mode 100644 toolkit/mozapps/extensions/amWebInstallListener.js delete mode 100644 toolkit/mozapps/extensions/content/OpenH264-license.txt delete mode 100644 toolkit/mozapps/extensions/content/about.js delete mode 100644 toolkit/mozapps/extensions/content/about.xul delete mode 100644 toolkit/mozapps/extensions/content/blocklist.css delete mode 100644 toolkit/mozapps/extensions/content/blocklist.js delete mode 100644 toolkit/mozapps/extensions/content/blocklist.xml delete mode 100644 toolkit/mozapps/extensions/content/blocklist.xul delete mode 100644 toolkit/mozapps/extensions/content/eula.js delete mode 100644 toolkit/mozapps/extensions/content/eula.xul delete mode 100644 toolkit/mozapps/extensions/content/extensions.css delete mode 100644 toolkit/mozapps/extensions/content/extensions.js delete mode 100644 toolkit/mozapps/extensions/content/extensions.xml delete mode 100644 toolkit/mozapps/extensions/content/extensions.xul delete mode 100644 toolkit/mozapps/extensions/content/gmpPrefs.xul delete mode 100644 toolkit/mozapps/extensions/content/list.js delete mode 100644 toolkit/mozapps/extensions/content/list.xul delete mode 100644 toolkit/mozapps/extensions/content/newaddon.js delete mode 100644 toolkit/mozapps/extensions/content/newaddon.xul delete mode 100644 toolkit/mozapps/extensions/content/pluginPrefs.xul delete mode 100644 toolkit/mozapps/extensions/content/setting.xml delete mode 100644 toolkit/mozapps/extensions/content/update.js delete mode 100644 toolkit/mozapps/extensions/content/update.xul delete mode 100644 toolkit/mozapps/extensions/content/updateinfo.xsl delete mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.css delete mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.js delete mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.xul delete mode 100644 toolkit/mozapps/extensions/content/xpinstallItem.xml delete mode 100644 toolkit/mozapps/extensions/docs/SystemAddons.rst delete mode 100644 toolkit/mozapps/extensions/docs/index.rst delete mode 100644 toolkit/mozapps/extensions/extensions.manifest delete mode 100644 toolkit/mozapps/extensions/internal/APIExtensionBootstrap.js delete mode 100644 toolkit/mozapps/extensions/internal/AddonConstants.jsm delete mode 100644 toolkit/mozapps/extensions/internal/AddonLogging.jsm delete mode 100644 toolkit/mozapps/extensions/internal/AddonRepository.jsm delete mode 100644 toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm delete mode 100644 toolkit/mozapps/extensions/internal/AddonTestUtils.jsm delete mode 100644 toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm delete mode 100644 toolkit/mozapps/extensions/internal/Content.js delete mode 100644 toolkit/mozapps/extensions/internal/E10SAddonsRollout.jsm delete mode 100644 toolkit/mozapps/extensions/internal/GMPProvider.jsm delete mode 100644 toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm delete mode 100644 toolkit/mozapps/extensions/internal/PluginProvider.jsm delete mode 100644 toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm delete mode 100644 toolkit/mozapps/extensions/internal/SpellCheckDictionaryBootstrap.js delete mode 100644 toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js delete mode 100644 toolkit/mozapps/extensions/internal/XPIProvider.jsm delete mode 100644 toolkit/mozapps/extensions/internal/XPIProviderUtils.js delete mode 100644 toolkit/mozapps/extensions/internal/moz.build delete mode 100644 toolkit/mozapps/extensions/jar.mn delete mode 100644 toolkit/mozapps/extensions/moz.build delete mode 100644 toolkit/mozapps/extensions/nsBlocklistService.js delete mode 100644 toolkit/mozapps/extensions/nsBlocklistServiceContent.js delete mode 100644 toolkit/mozapps/extensions/test/AddonManagerTesting.jsm delete mode 100644 toolkit/mozapps/extensions/test/Makefile.in delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/bootstrap_globals/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/bootstrap_globals/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/min1max1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/min1max2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/min1max3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/min1max3b/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/override1x2-1x3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/icon.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/preview.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/version.jsm delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/version.jsm delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/version.jsm delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap2_1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap2_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap_const/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_a_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_a_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_b_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_b_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_c_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_c_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_d_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_d_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_e_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_e_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_f_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_f_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_g_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_g_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_7/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_8/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_9/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug371495/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug394300_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug394300_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug397778/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug425657/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug521905/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567173/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567184/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567184/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/testfile delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/testfile1 delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/testfile delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/testfile2 delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug594058/directory/file1 delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug594058/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug595573/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug659772/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/test.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_bug757663/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_cacheflush1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_cacheflush2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/inner.jar delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/components.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/other/something.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_6/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_data_directory/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_db_sanity_1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_db_sanity_1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_complete_v2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_complete_v2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_complete_webextension_v2/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_defer_v2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_defer_v2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_defer_webextension_v2/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_ignore_v2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_ignore_v2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_delay_update_ignore_webextension_v2/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary/dictionaries/ab-CD.dic delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_2/dictionaries/ab-CD.dic delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_distribution1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_experiment1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_experiment1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_filepointer/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/icon.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/subdir/subfile.txt delete mode 100644 toolkit/mozapps/extensions/test/addons/test_hotfix_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_hotfix_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/icon.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/icon64.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_1/icon.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon4.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon5.jar delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon6.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon7.jar delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/badaddon.jar delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/badaddon.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/icon.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install5/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install7/addon1.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install7/addon2.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install7/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_install8/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/harness-options.json delete mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_langpack/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_langpack/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_locale/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_locked2_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_locked2_6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate4_7/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate7/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate8/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate8/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate9/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_symbol/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_symbol/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_theme/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_theme/preview.png delete mode 100644 toolkit/mozapps/extensions/test/addons/test_undoincompatible/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_undoincompatible/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_undouninstall1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_undouninstall1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update12/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update8/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update_multi1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update_multi1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update_multi2/addon.xpi delete mode 100644 toolkit/mozapps/extensions/test/addons/test_update_multi2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/upgradeable1x2-3_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/upgradeable1x2-3_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_1/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_1/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_2/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_3/_locales/en/messages.json delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_3/_locales/fr/messages.json delete mode 100644 toolkit/mozapps/extensions/test/addons/webextension_3/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/browser/.eslintrc.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addon_about.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/addon_prefs.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_10.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_10/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_3.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_3/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_4.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_4/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_5.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_5/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_6.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_6/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_7.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_7/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_8_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_8_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_9_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_9_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_experiment1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_experiment1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/options.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/settings.dtd delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/options.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/options.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_installssl.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_installssl/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_searching.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_searching/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_searching/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/frame-script.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/chrome.manifest delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/frame-script.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_webapi_install.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_webapi_install/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_webapi_install/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/options_signed.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/options_signed/manifest.json delete mode 100644 toolkit/mozapps/extensions/test/browser/addons/options_signed/options.html delete mode 100644 toolkit/mozapps/extensions/test/browser/blockNoPlugins.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/blockPluginHard.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser-common.ini delete mode 100644 toolkit/mozapps/extensions/test/browser/browser-window.ini delete mode 100644 toolkit/mozapps/extensions/test/browser/browser.ini delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_about.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_addonrepository_performance.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug523784.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557943.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956_8_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956_9_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562797.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562854.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562890.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562899.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562992.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug567127.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug567137.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug570760.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug572561.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug573062.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug577990.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug580298.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug581076.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug586574.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug587970.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug590347.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591465.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591465.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591663.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug593535.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug593535.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug596336.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug608316.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug610764.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug616841.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug618502.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug679604.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug714593.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_checkAddonCompatibility.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_details.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_discovery.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_discovery_install.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_dragdrop.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_eula.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_eula.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_experiments.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_globalwarnings.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_hotfix.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings_custom.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.rdf^headers^ delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_install1_3.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_installssl.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_list.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_manualupdates.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_metadataTimeout.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_newaddon.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_openDialog.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_plugin_enabled_state_locked.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_pluginprefs.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_recentupdates.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching_empty.xml delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_sorting.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_sorting_plugins.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_system_addons_are_e10s.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_tabsettings.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_task_next_test.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_types.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_uninstalling.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_update.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_updateid.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.rdf^headers^ delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_access.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_addon_listener.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_enable.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_install.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_uninstall.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webext_options.js delete mode 100644 toolkit/mozapps/extensions/test/browser/cancelCompatCheck.sjs delete mode 100644 toolkit/mozapps/extensions/test/browser/discovery.html delete mode 100644 toolkit/mozapps/extensions/test/browser/discovery_frame.html delete mode 100644 toolkit/mozapps/extensions/test/browser/discovery_install.html delete mode 100644 toolkit/mozapps/extensions/test/browser/head.js delete mode 100644 toolkit/mozapps/extensions/test/browser/more_options.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/moz.build delete mode 100644 toolkit/mozapps/extensions/test/browser/options.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/plugin_test.html delete mode 100644 toolkit/mozapps/extensions/test/browser/redirect.sjs delete mode 100644 toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml delete mode 100644 toolkit/mozapps/extensions/test/browser/signed_hotfix.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/unsigned_hotfix.rdf delete mode 100644 toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi delete mode 100644 toolkit/mozapps/extensions/test/browser/webapi_addon_listener.html delete mode 100644 toolkit/mozapps/extensions/test/browser/webapi_checkavailable.html delete mode 100644 toolkit/mozapps/extensions/test/browser/webapi_checkchromeframe.xul delete mode 100644 toolkit/mozapps/extensions/test/browser/webapi_checkframed.html delete mode 100644 toolkit/mozapps/extensions/test/browser/webapi_checknavigatedwindow.html delete mode 100644 toolkit/mozapps/extensions/test/mochitest/.eslintrc.js delete mode 100644 toolkit/mozapps/extensions/test/mochitest/file_bug687194.xpi delete mode 100644 toolkit/mozapps/extensions/test/mochitest/file_empty.html delete mode 100644 toolkit/mozapps/extensions/test/mochitest/mochitest.ini delete mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug609794.html delete mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug687194.html delete mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug887098.html delete mode 100644 toolkit/mozapps/extensions/test/moz.build delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/.eslintrc.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/BootstrapMonitor.jsm delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_block.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_empty.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_start.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_warn.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/corrupt.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/corruptfile.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/empty.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/from_sources/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/from_sources/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/pluginInfoURL_block.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/bad.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/bad.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/bad2.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/empty.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/good.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/missing.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/productaddons/unsigned.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_1/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_1/test.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/bootstrap_2/test.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_badid.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_broken.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_good.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long_63_hash.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long_63_plain.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long_64_hash.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long_64_plain.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/long_65_hash.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/multi_badid.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/multi_broken.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/multi_signed.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/multi_unsigned.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/nonbootstrap_1/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/nonbootstrap_1/test.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/nonbootstrap_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/nonbootstrap_2/test.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/unsigned_bootstrap_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/unsigned_nonbootstrap_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system1_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system1_1_badcert.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system1_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system2_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system2_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system2_3.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system3_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system3_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system3_3.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system4_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system5_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system6_1_unpack.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system6_2_notBootstrap.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system6_3_notMultiprocess.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_complete.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_complete_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_defer.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_defer_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_defer_also.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_defer_also_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_ignore.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_delay_ignore_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/system_addons/system_failed_update.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_cache.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_ignore.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_normal.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_strict.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_empty.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_failed.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_getAddonsByIDs.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_backgroundupdate.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_prefs_1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug299716.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug299716_2.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug324121.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug393285.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug394300.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug424262.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug449027_app.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug449027_toolkit.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug468528.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_1.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_2.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_3.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_4.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_5.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_1.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_2.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_3.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_4.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_5.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_2.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_empty.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_outdated_1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_outdated_2.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug526598_1.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug526598_2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug541420.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug542391.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug554133.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug619730.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug655254.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_compatoverrides.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_corrupt.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_update_complete/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_update_defer/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_update_ignore/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_complete.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_complete.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_defer.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_defer.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_ignore.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_delay_updates_ignore.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_dictionary.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/subdir/dummy.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/subdir/subdir2/dummy2.txt delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.xml delete mode 100755 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_hotfix_1.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_hotfix_2.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_hotfix_3.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_install.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_install.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_migrate.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_no_update.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/ancient.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/new.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/old.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_pluginBlocklistCtp.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_pluginBlocklistCtpUndo.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_proxy/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_softblocked1.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_sourceURI.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_temporary/bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update.xml delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update_multi.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecheck.json delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecheck.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_ignore.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_normal.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_strict.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/unsigned.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/webext-implicit-id.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/head_addons.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/head_unpack.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_compatmode.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_ChromeManifestParser.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_DeferredSave.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_ProductAddonChecker.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_XPIcancel.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_addon_path_service.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_asyncBlocklistLoad.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_badschema.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_gfx.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_const.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_globals.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_resource.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug1180901.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug1180901_2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug299716.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug299716_2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug324121.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug371495.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug384052.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug394300.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug397778.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug424262.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug425657.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug449027.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug465190.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug468528.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_1.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_1_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_3.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_3_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_4.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_1.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_3.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug521905.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug526598.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug541420.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug542391.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug554133.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug559800.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug563256.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug564030.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug566626.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug567184.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug569138.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug570173.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug576735.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug587088.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug594058.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug595081.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug595573.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug596607.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug616841.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug619730.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug620837.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug655254.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug740612.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug753900.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug757663.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug953156.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_cache_certdb.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_checkCompatibility_themeOverride.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_checkcompatibility.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_childprocess.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_compatoverrides.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corrupt_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corruptfile.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dataDirectory.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_default_providers_pref.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_delay_update.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dependencies.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_disable.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_distribution.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dss.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_duplicateplugins.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_e10s_restartless.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_error.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_experiment.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_ext_management.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_filepointer.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_fuel.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_general.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_getresource.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js delete mode 100755 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gmpProvider.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_hasbinarycomponents.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_hotfix.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_hotfix_cert.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install_from_sources.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install_icons.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_isDebuggable.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_isReady.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_json_updatecheck.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_langpack.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locale.js delete mode 100755 toolkit/mozapps/extensions/test/xpcshell/test_locked.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locked2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locked_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_manifest.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_mapURIToAddonID.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_metadata_update.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate5.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrateAddonRepository.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate_max_version.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_nodisable_hidden.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_onPropertyChanged_appDisabled.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pass_symbol.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_permissions.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginBlocklistCtp.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginInfoURL.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginchange.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_plugins.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pref_properties.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_unsafe_access_shutdown.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_unsafe_access_startup.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_proxies.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_proxy.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_registry.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_reload.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_safemode.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_schema_change.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_seen.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_seen_newprofile.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_shutdown.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_install.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_long.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_migrate.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_multi.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_updatepref.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_sourceURI.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_startup.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_strictcompatibility.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_switch_os.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_system_reset.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_system_update.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_targetPlatforms.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_temporary.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_theme.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_types.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_undothemeuninstall.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_undouninstall.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_uninstall.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_compatmode.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_ignorecompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updatecheck.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updateid.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_upgrade.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_upgrade_strictcompat.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_webextension.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_webextension_embedded.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_webextension_icons.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_webextension_paths.js delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell-unpack.ini delete mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/.eslintrc.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/amosigned2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/authRedirect.sjs delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser.ini delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_trigger_iframe.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_amosigned_url.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badargs.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badargs2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badhash.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badhashtype.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug540558.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug611242.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug638292.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cancel.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_concurrent_installs.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_datauri.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_empty.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_hash.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_installchrome.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_multipackage.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_offline.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_relative.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_multipackage.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_multiple.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_naming.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_tampered.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_trigger.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_untrusted.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_url.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_softwareupdate.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_switchtab.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_url.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist3.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist7.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug540558.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug638292.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug645699.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/concurrent_installs.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/empty.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/enabled.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/head.js delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/installchrome.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/installtrigger.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/navigate.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/redirect.sjs delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/restartless.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-multipackage.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed2.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/theme.xpi delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html delete mode 100644 toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi create mode 100644 toolkit/mozapps/webextensions/.eslintrc.js create mode 100644 toolkit/mozapps/webextensions/AddonContentPolicy.cpp create mode 100644 toolkit/mozapps/webextensions/AddonContentPolicy.h create mode 100644 toolkit/mozapps/webextensions/AddonManager.jsm create mode 100644 toolkit/mozapps/webextensions/AddonManagerWebAPI.cpp create mode 100644 toolkit/mozapps/webextensions/AddonManagerWebAPI.h create mode 100644 toolkit/mozapps/webextensions/AddonPathService.cpp create mode 100644 toolkit/mozapps/webextensions/AddonPathService.h create mode 100644 toolkit/mozapps/webextensions/ChromeManifestParser.jsm create mode 100644 toolkit/mozapps/webextensions/DeferredSave.jsm create mode 100644 toolkit/mozapps/webextensions/LightweightThemeManager.jsm create mode 100644 toolkit/mozapps/webextensions/addonManager.js create mode 100644 toolkit/mozapps/webextensions/amContentHandler.js create mode 100644 toolkit/mozapps/webextensions/amIAddonManager.idl create mode 100644 toolkit/mozapps/webextensions/amIAddonPathService.idl create mode 100644 toolkit/mozapps/webextensions/amIWebInstallListener.idl create mode 100644 toolkit/mozapps/webextensions/amIWebInstaller.idl create mode 100644 toolkit/mozapps/webextensions/amInstallTrigger.js create mode 100644 toolkit/mozapps/webextensions/amWebAPI.js create mode 100644 toolkit/mozapps/webextensions/amWebInstallListener.js create mode 100644 toolkit/mozapps/webextensions/content/OpenH264-license.txt create mode 100644 toolkit/mozapps/webextensions/content/about.js create mode 100644 toolkit/mozapps/webextensions/content/about.xul create mode 100644 toolkit/mozapps/webextensions/content/blocklist.css create mode 100644 toolkit/mozapps/webextensions/content/blocklist.js create mode 100644 toolkit/mozapps/webextensions/content/blocklist.xml create mode 100644 toolkit/mozapps/webextensions/content/blocklist.xul create mode 100644 toolkit/mozapps/webextensions/content/eula.js create mode 100644 toolkit/mozapps/webextensions/content/eula.xul create mode 100644 toolkit/mozapps/webextensions/content/extensions.css create mode 100644 toolkit/mozapps/webextensions/content/extensions.js create mode 100644 toolkit/mozapps/webextensions/content/extensions.xml create mode 100644 toolkit/mozapps/webextensions/content/extensions.xul create mode 100644 toolkit/mozapps/webextensions/content/gmpPrefs.xul create mode 100644 toolkit/mozapps/webextensions/content/list.js create mode 100644 toolkit/mozapps/webextensions/content/list.xul create mode 100644 toolkit/mozapps/webextensions/content/newaddon.js create mode 100644 toolkit/mozapps/webextensions/content/newaddon.xul create mode 100644 toolkit/mozapps/webextensions/content/pluginPrefs.xul create mode 100644 toolkit/mozapps/webextensions/content/setting.xml create mode 100644 toolkit/mozapps/webextensions/content/update.js create mode 100644 toolkit/mozapps/webextensions/content/update.xul create mode 100644 toolkit/mozapps/webextensions/content/updateinfo.xsl create mode 100644 toolkit/mozapps/webextensions/content/xpinstallConfirm.css create mode 100644 toolkit/mozapps/webextensions/content/xpinstallConfirm.js create mode 100644 toolkit/mozapps/webextensions/content/xpinstallConfirm.xul create mode 100644 toolkit/mozapps/webextensions/content/xpinstallItem.xml create mode 100644 toolkit/mozapps/webextensions/docs/SystemAddons.rst create mode 100644 toolkit/mozapps/webextensions/docs/index.rst create mode 100644 toolkit/mozapps/webextensions/extensions.manifest create mode 100644 toolkit/mozapps/webextensions/internal/APIExtensionBootstrap.js create mode 100644 toolkit/mozapps/webextensions/internal/AddonConstants.jsm create mode 100644 toolkit/mozapps/webextensions/internal/AddonLogging.jsm create mode 100644 toolkit/mozapps/webextensions/internal/AddonRepository.jsm create mode 100644 toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm create mode 100644 toolkit/mozapps/webextensions/internal/AddonTestUtils.jsm create mode 100644 toolkit/mozapps/webextensions/internal/AddonUpdateChecker.jsm create mode 100644 toolkit/mozapps/webextensions/internal/Content.js create mode 100644 toolkit/mozapps/webextensions/internal/E10SAddonsRollout.jsm create mode 100644 toolkit/mozapps/webextensions/internal/GMPProvider.jsm create mode 100644 toolkit/mozapps/webextensions/internal/LightweightThemeImageOptimizer.jsm create mode 100644 toolkit/mozapps/webextensions/internal/PluginProvider.jsm create mode 100644 toolkit/mozapps/webextensions/internal/ProductAddonChecker.jsm create mode 100644 toolkit/mozapps/webextensions/internal/SpellCheckDictionaryBootstrap.js create mode 100644 toolkit/mozapps/webextensions/internal/WebExtensionBootstrap.js create mode 100644 toolkit/mozapps/webextensions/internal/XPIProvider.jsm create mode 100644 toolkit/mozapps/webextensions/internal/XPIProviderUtils.js create mode 100644 toolkit/mozapps/webextensions/internal/moz.build create mode 100644 toolkit/mozapps/webextensions/jar.mn create mode 100644 toolkit/mozapps/webextensions/moz.build create mode 100644 toolkit/mozapps/webextensions/nsBlocklistService.js create mode 100644 toolkit/mozapps/webextensions/nsBlocklistServiceContent.js create mode 100644 toolkit/mozapps/webextensions/test/AddonManagerTesting.jsm create mode 100644 toolkit/mozapps/webextensions/test/Makefile.in create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_hard1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_hard1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_hard1_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_regexp1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_regexp1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_regexp1_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft1_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft2_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft2_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft2_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft3_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft3_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft3_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft4_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft4_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft4_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft5_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft5_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/blocklist_soft5_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/bootstrap_globals/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/bootstrap_globals/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/min1max1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/min1max2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/min1max3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/min1max3b/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/override1x2-1x3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_AddonRepository_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_AddonRepository_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_AddonRepository_3/icon.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_AddonRepository_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_AddonRepository_3/preview.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_1/version.jsm create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_2/version.jsm create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_3/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_3/version.jsm create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap1_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap2_1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap2_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap_const/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bootstrap_const/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_a_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_a_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_b_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_b_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_c_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_c_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_d_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_d_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_e_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_e_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_f_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_f_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_g_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug299716_g_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_7/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_8/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug324121_9/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug335238_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug335238_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug335238_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug335238_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug371495/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug394300_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug394300_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug397778/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug425657/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug470377_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug470377_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug470377_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug470377_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug470377_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug521905/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug567173/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug567184/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug567184/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_1/testfile create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_1/testfile1 create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_2/testfile create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug587088_2/testfile2 create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug594058/directory/file1 create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug594058/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug595573/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug655254/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug655254_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug655254_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug659772/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug675371/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug675371/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug675371/test.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug740612_1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug740612_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug740612_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug740612_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_bug757663/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_cacheflush1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_cacheflush2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_1/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_2/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_3/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_3/inner.jar create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_4/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_4/components/components.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_4/components/other/something.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_5/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_6/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_chromemanifest_6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_data_directory/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_db_sanity_1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_db_sanity_1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_complete_v2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_complete_v2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_complete_webextension_v2/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_defer_v2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_defer_v2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_defer_webextension_v2/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_ignore_v2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_ignore_v2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_delay_update_ignore_webextension_v2/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary/dictionaries/ab-CD.dic create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary_2/dictionaries/ab-CD.dic create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_dictionary_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_distribution1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_experiment1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_experiment1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_filepointer/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_getresource/icon.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_getresource/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_getresource/subdir/subfile.txt create mode 100644 toolkit/mozapps/webextensions/test/addons/test_hotfix_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_hotfix_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install1/icon.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install1/icon64.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install2_1/icon.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install2_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install2_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/addon4.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/addon5.jar create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/addon6.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/addon7.jar create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/badaddon.jar create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/badaddon.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/icon.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install5/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install7/addon1.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install7/addon2.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install7/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_install8/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_jetpack/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_jetpack/harness-options.json create mode 100644 toolkit/mozapps/webextensions/test/addons/test_jetpack/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_langpack/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_langpack/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_locale/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_locked2_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_locked2_6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate4_6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate4_7/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate7/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate8/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate8/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_migrate9/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_symbol/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_symbol/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_theme/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_theme/preview.png create mode 100644 toolkit/mozapps/webextensions/test/addons/test_undoincompatible/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_undoincompatible/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_undouninstall1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_undouninstall1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update12/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update8/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update_multi1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update_multi1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update_multi2/addon.xpi create mode 100644 toolkit/mozapps/webextensions/test/addons/test_update_multi2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_updateid1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_updateid1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/test_updateid2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/addons/test_updateid2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/upgradeable1x2-3_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/upgradeable1x2-3_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_1/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_1/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_2/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_3/_locales/en/messages.json create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_3/_locales/fr/messages.json create mode 100644 toolkit/mozapps/webextensions/test/addons/webextension_3/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/browser/.eslintrc.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addon_about.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/addon_prefs.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/options.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/settings.dtd create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/options.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/options.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_installssl/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_searching/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_searching/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/frame-script.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/chrome.manifest create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/frame-script.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/options_signed/manifest.json create mode 100644 toolkit/mozapps/webextensions/test/browser/addons/options_signed/options.html create mode 100644 toolkit/mozapps/webextensions/test/browser/blockNoPlugins.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/blockPluginHard.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser-common.ini create mode 100644 toolkit/mozapps/webextensions/test/browser/browser-window.ini create mode 100644 toolkit/mozapps/webextensions/test/browser/browser.ini create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_CTP_plugins.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_about.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_addonrepository_performance.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug523784.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557943.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557956.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557956.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557956.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug562797.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug562854.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug562890.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug562899.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug562992.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug567127.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug567137.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug570760.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug572561.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug573062.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug577990.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug580298.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug581076.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug586574.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug587970.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug590347.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug591465.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug591465.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug591663.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug593535.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug593535.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug596336.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug608316.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug610764.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug616841.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug618502.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug679604.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_bug714593.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_cancelCompatCheck.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_checkAddonCompatibility.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_details.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_discovery.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_discovery_install.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_dragdrop.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_eula.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_eula.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_experiments.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_globalwarnings.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_gmpProvider.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_hotfix.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_inlinesettings.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_browser.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_custom.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_info.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_install.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_install.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_install.rdf^headers^ create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_install.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_installssl.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_list.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_manualupdates.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_metadataTimeout.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_newaddon.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_openDialog.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_plugin_enabled_state_locked.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_pluginprefs.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_purchase.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_purchase.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_recentupdates.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_searching.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_searching.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_searching_empty.xml create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_sorting.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_sorting_plugins.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_system_addons_are_e10s.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_tabsettings.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_task_next_test.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_types.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_uninstalling.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_update.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_updateid.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_updatessl.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf^headers^ create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi_access.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi_addon_listener.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi_enable.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi_install.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webapi_uninstall.js create mode 100644 toolkit/mozapps/webextensions/test/browser/browser_webext_options.js create mode 100644 toolkit/mozapps/webextensions/test/browser/cancelCompatCheck.sjs create mode 100644 toolkit/mozapps/webextensions/test/browser/discovery.html create mode 100644 toolkit/mozapps/webextensions/test/browser/discovery_frame.html create mode 100644 toolkit/mozapps/webextensions/test/browser/discovery_install.html create mode 100644 toolkit/mozapps/webextensions/test/browser/head.js create mode 100644 toolkit/mozapps/webextensions/test/browser/more_options.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/moz.build create mode 100644 toolkit/mozapps/webextensions/test/browser/options.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/plugin_test.html create mode 100644 toolkit/mozapps/webextensions/test/browser/redirect.sjs create mode 100644 toolkit/mozapps/webextensions/test/browser/releaseNotes.xhtml create mode 100644 toolkit/mozapps/webextensions/test/browser/signed_hotfix.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.rdf create mode 100644 toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpi create mode 100644 toolkit/mozapps/webextensions/test/browser/webapi_addon_listener.html create mode 100644 toolkit/mozapps/webextensions/test/browser/webapi_checkavailable.html create mode 100644 toolkit/mozapps/webextensions/test/browser/webapi_checkchromeframe.xul create mode 100644 toolkit/mozapps/webextensions/test/browser/webapi_checkframed.html create mode 100644 toolkit/mozapps/webextensions/test/browser/webapi_checknavigatedwindow.html create mode 100644 toolkit/mozapps/webextensions/test/mochitest/.eslintrc.js create mode 100644 toolkit/mozapps/webextensions/test/mochitest/file_bug687194.xpi create mode 100644 toolkit/mozapps/webextensions/test/mochitest/file_empty.html create mode 100644 toolkit/mozapps/webextensions/test/mochitest/mochitest.ini create mode 100644 toolkit/mozapps/webextensions/test/mochitest/test_bug609794.html create mode 100644 toolkit/mozapps/webextensions/test/mochitest/test_bug687194.html create mode 100644 toolkit/mozapps/webextensions/test/mochitest/test_bug887098.html create mode 100644 toolkit/mozapps/webextensions/test/moz.build create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/.eslintrc.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/BootstrapMonitor.jsm create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/addon_change.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/addon_update1.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/addon_update2.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/addon_update3.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/app_update.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/blocklistchange/manual_update.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/bug455906_block.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/bug455906_empty.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/bug455906_start.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/bug455906_warn.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/corrupt.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/corruptfile.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/empty.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/from_sources/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/from_sources/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/pluginInfoURL_block.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/bad.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/bad.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/bad2.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/empty.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/good.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/missing.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/productaddons/unsigned.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_1/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_1/test.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/bootstrap_2/test.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/hotfix_badid.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/hotfix_broken.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/hotfix_good.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/long_63_hash.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/long_63_plain.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/long_64_hash.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/long_64_plain.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/long_65_hash.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/multi_badid.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/multi_broken.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/multi_signed.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/multi_unsigned.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/nonbootstrap_1/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/nonbootstrap_1/test.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/nonbootstrap_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/nonbootstrap_2/test.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/preliminary_bootstrap_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/signed_bootstrap_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/signed_bootstrap_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/signed_bootstrap_badid_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/signed_nonbootstrap_badid_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/unsigned_bootstrap_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/signing_checks/unsigned_nonbootstrap_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system1_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system1_1_badcert.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system1_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system2_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system2_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system2_3.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system3_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system3_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system3_3.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system4_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system5_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system6_1_unpack.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system6_2_notBootstrap.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system6_3_notMultiprocess.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_complete.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_complete_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_defer.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_defer_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_defer_also.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_defer_also_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_ignore.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_delay_ignore_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/system_addons/system_failed_update.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_cache.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_compatmode_ignore.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_compatmode_normal.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_compatmode_strict.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_empty.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_failed.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_AddonRepository_getAddonsByIDs.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_backgroundupdate.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_blocklist_prefs_1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_blocklist_regexp_1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug299716.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug299716_2.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug324121.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug393285.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug394300.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug424262.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug449027_app.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug449027_toolkit.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug468528.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/install_1.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/install_2.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/install_3.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/install_4.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/install_5.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/update_1.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/update_2.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/update_3.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/update_4.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug470377/update_5.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug514327_1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug514327_2.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug514327_3_empty.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug514327_3_outdated_1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug514327_3_outdated_2.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug526598_1.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug526598_2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug541420.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug542391.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug554133.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug619730.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_bug655254.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_compatoverrides.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_corrupt.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_update_complete/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_update_defer/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_update_ignore/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_complete.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_complete.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_defer.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_defer.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_ignore.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_delay_updates_ignore.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_dictionary.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_distribution2_2/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_distribution2_2/install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_distribution2_2/subdir/dummy.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_distribution2_2/subdir/subdir2/dummy2.txt create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_gfxBlacklist.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_gfxBlacklist2.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_hotfix_1.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_hotfix_2.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_hotfix_3.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_install.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_install.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_migrate.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_migrate4.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_no_update.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_overrideblocklist/ancient.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_overrideblocklist/new.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_overrideblocklist/old.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_pluginBlocklistCtp.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_pluginBlocklistCtpUndo.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_proxy/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_softblocked1.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_sourceURI.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_temporary/bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_update.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_update.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_update.xml create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_update_multi.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updatecheck.json create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updatecheck.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updatecompatmode_ignore.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updatecompatmode_normal.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updatecompatmode_strict.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/test_updateid.rdf create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/unsigned.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/data/webext-implicit-id.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/head_addons.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/head_unpack.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_AddonRepository.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_AddonRepository_cache.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_AddonRepository_compatmode.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_ChromeManifestParser.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_DeferredSave.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_LightweightThemeManager.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_ProductAddonChecker.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_XPIStates.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_XPIcancel.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_addon_path_service.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_asyncBlocklistLoad.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_backgroundupdate.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bad_json.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_badschema.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_blocklist_gfx.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_blocklist_metadata_filters.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_blocklist_prefs.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_blocklist_regexp.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_blocklistchange.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap_const.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap_globals.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap_resource.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug1180901.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug1180901_2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug299716.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug299716_2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug324121.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug335238.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug371495.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug384052.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug393285.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug394300.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug397778.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug406118.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug424262.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug425657.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug430120.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug449027.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug455906.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug465190.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug468528.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_1.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_1_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_3.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_3_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug470377_4.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug514327_1.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug514327_2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug514327_3.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug521905.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug526598.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug541420.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug542391.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug554133.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug559800.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug563256.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug564030.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug566626.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug567184.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug569138.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug570173.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug576735.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug587088.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug594058.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug595081.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug595573.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug596607.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug616841.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug619730.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug620837.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug655254.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug659772.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug675371.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug740612.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug753900.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug757663.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_bug953156.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_cache_certdb.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_cacheflush.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_checkCompatibility_themeOverride.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_checkcompatibility.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_childprocess.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_compatoverrides.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_corrupt.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_corrupt_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_corruptfile.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_dataDirectory.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_default_providers_pref.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_delay_update.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_delay_update_webextension.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_dependencies.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_dictionary.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_disable.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_distribution.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_dss.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_duplicateplugins.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_e10s_restartless.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_error.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_experiment.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_ext_management.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_filepointer.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_fuel.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_general.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_getresource.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Device.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_DriverNew.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_OK.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_OS.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Vendor.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_Version.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gfxBlacklist_prefs.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_gmpProvider.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_hasbinarycomponents.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_hotfix.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_hotfix_cert.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_install.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_install_from_sources.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_install_icons.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_install_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_isDebuggable.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_isReady.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_json_updatecheck.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_langpack.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_locale.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_locked.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_locked2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_locked_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_manifest.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_mapURIToAddonID.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_metadata_update.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate1.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate2.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate3.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate4.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate5.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrateAddonRepository.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_migrate_max_version.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_multiprocessCompatible.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_no_addons.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_nodisable_hidden.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_onPropertyChanged_appDisabled.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_overrideblocklist.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_pass_symbol.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_permissions.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_permissions_prefs.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_pluginBlocklistCtp.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_pluginInfoURL.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_pluginchange.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_plugins.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_pref_properties.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_provider_markSafe.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_provider_shutdown.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_provider_unsafe_access_shutdown.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_provider_unsafe_access_startup.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_proxies.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_proxy.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_registry.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_reload.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_safemode.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_schema_change.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_seen.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_seen_newprofile.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_shutdown.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_inject.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_install.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_long.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_migrate.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_multi.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_updatepref.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_signed_verify.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_softblocked.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_sourceURI.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_startup.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_strictcompatibility.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_switch_os.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_syncGUID.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_system_delay_update.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_system_reset.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_system_update.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_targetPlatforms.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_temporary.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_theme.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_types.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_undothemeuninstall.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_undouninstall.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_uninstall.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_update.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_updateCancel.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_update_compatmode.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_update_ignorecompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_update_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_update_webextensions.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_updatecheck.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_updateid.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_upgrade.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_upgrade_strictcompat.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_webextension.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_webextension_embedded.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_webextension_icons.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_webextension_install.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/test_webextension_paths.js create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/xpcshell-shared.ini create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/xpcshell-unpack.ini create mode 100644 toolkit/mozapps/webextensions/test/xpcshell/xpcshell.ini create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/.eslintrc.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/amosigned.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/amosigned2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/authRedirect.sjs create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser.ini create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_amosigned_trigger.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_amosigned_trigger_iframe.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_amosigned_url.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_auth.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_auth2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_auth3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_auth4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_badargs.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_badargs2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_badhash.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_badhashtype.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_bug540558.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_bug611242.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_bug638292.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_bug645699.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_bug672485.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_cancel.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_concurrent_installs.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_cookies.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_cookies2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_cookies3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_cookies4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_corrupt.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_datauri.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_empty.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_enabled.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_enabled2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_enabled3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_hash.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_hash2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash5.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_httphash6.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_installchrome.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_localfile.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_localfile2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_localfile3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_localfile4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_multipackage.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_navigateaway.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_navigateaway2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_navigateaway3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_navigateaway4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_offline.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_relative.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_multipackage.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_multiple.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_naming.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_tampered.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_trigger.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_untrusted.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_signed_url.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_softwareupdate.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_switchtab.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_trigger_redirect.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_unsigned_trigger.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_unsigned_trigger_iframe.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_unsigned_trigger_xorigin.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_unsigned_url.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist2.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist3.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist4.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist5.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist6.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/browser_whitelist7.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/bug540558.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/bug638292.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/bug645699.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/concurrent_installs.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/cookieRedirect.sjs create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/corrupt.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/empty.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/enabled.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/hashRedirect.sjs create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/head.js create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/incompatible.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/installchrome.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/installtrigger.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/installtrigger_frame.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/multipackage.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/navigate.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/redirect.sjs create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/restartless-unsigned.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/restartless.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed-multipackage.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed-no-cn.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed-no-o.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed-tampered.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed-untrusted.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/signed2.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/slowinstall.sjs create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/startsoftwareupdate.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/theme.xpi create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/triggerredirect.html create mode 100644 toolkit/mozapps/webextensions/test/xpinstall/unsigned.xpi (limited to 'toolkit/mozapps') diff --git a/toolkit/mozapps/extensions/.eslintrc.js b/toolkit/mozapps/extensions/.eslintrc.js deleted file mode 100644 index 2b90bd053..000000000 --- a/toolkit/mozapps/extensions/.eslintrc.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -module.exports = { // eslint-disable-line no-undef - "rules": { - // No using undeclared variables - "no-undef": "error", - } -}; diff --git a/toolkit/mozapps/extensions/AddonContentPolicy.cpp b/toolkit/mozapps/extensions/AddonContentPolicy.cpp deleted file mode 100644 index 90e53b2ea..000000000 --- a/toolkit/mozapps/extensions/AddonContentPolicy.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AddonContentPolicy.h" - -#include "mozilla/dom/nsCSPUtils.h" -#include "nsCOMPtr.h" -#include "nsContentPolicyUtils.h" -#include "nsContentTypeParser.h" -#include "nsContentUtils.h" -#include "nsIConsoleService.h" -#include "nsIContentSecurityPolicy.h" -#include "nsIContent.h" -#include "nsIDocument.h" -#include "nsIEffectiveTLDService.h" -#include "nsIScriptError.h" -#include "nsIStringBundle.h" -#include "nsIUUIDGenerator.h" -#include "nsIURI.h" -#include "nsNetCID.h" -#include "nsNetUtil.h" - -using namespace mozilla; - -/* Enforces content policies for WebExtension scopes. Currently: - * - * - Prevents loading scripts with a non-default JavaScript version. - * - Checks custom content security policies for sufficiently stringent - * script-src and object-src directives. - */ - -#define VERSIONED_JS_BLOCKED_MESSAGE \ - u"Versioned JavaScript is a non-standard, deprecated extension, and is " \ - u"not supported in WebExtension code. For alternatives, please see: " \ - u"https://developer.mozilla.org/Add-ons/WebExtensions/Tips" - -AddonContentPolicy::AddonContentPolicy() -{ -} - -AddonContentPolicy::~AddonContentPolicy() -{ -} - -NS_IMPL_ISUPPORTS(AddonContentPolicy, nsIContentPolicy, nsIAddonContentPolicy) - -static nsresult -GetWindowIDFromContext(nsISupports* aContext, uint64_t *aResult) -{ - NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE); - - nsCOMPtr content = do_QueryInterface(aContext); - NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); - - nsCOMPtr document = content->OwnerDoc(); - NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); - - nsCOMPtr window = document->GetInnerWindow(); - NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); - - *aResult = window->WindowID(); - return NS_OK; -} - -static nsresult -LogMessage(const nsAString &aMessage, nsIURI* aSourceURI, const nsAString &aSourceSample, - nsISupports* aContext) -{ - nsCOMPtr error = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); - NS_ENSURE_TRUE(error, NS_ERROR_OUT_OF_MEMORY); - - nsCString sourceName = aSourceURI->GetSpecOrDefault(); - - uint64_t windowID = 0; - GetWindowIDFromContext(aContext, &windowID); - - nsresult rv = - error->InitWithWindowID(aMessage, NS_ConvertUTF8toUTF16(sourceName), - aSourceSample, 0, 0, nsIScriptError::errorFlag, - "JavaScript", windowID); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr console = do_GetService(NS_CONSOLESERVICE_CONTRACTID); - NS_ENSURE_TRUE(console, NS_ERROR_OUT_OF_MEMORY); - - console->LogMessage(error); - return NS_OK; -} - - -// Content policy enforcement: - -NS_IMETHODIMP -AddonContentPolicy::ShouldLoad(uint32_t aContentType, - nsIURI* aContentLocation, - nsIURI* aRequestOrigin, - nsISupports* aContext, - const nsACString& aMimeTypeGuess, - nsISupports* aExtra, - nsIPrincipal* aRequestPrincipal, - int16_t* aShouldLoad) -{ - MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), - "We should only see external content policy types here."); - - *aShouldLoad = nsIContentPolicy::ACCEPT; - - if (!aRequestOrigin) { - return NS_OK; - } - - // Only apply this policy to requests from documents loaded from - // moz-extension URLs, or to resources being loaded from moz-extension URLs. - bool equals; - if (!((NS_SUCCEEDED(aContentLocation->SchemeIs("moz-extension", &equals)) && equals) || - (NS_SUCCEEDED(aRequestOrigin->SchemeIs("moz-extension", &equals)) && equals))) { - return NS_OK; - } - - if (aContentType == nsIContentPolicy::TYPE_SCRIPT) { - NS_ConvertUTF8toUTF16 typeString(aMimeTypeGuess); - nsContentTypeParser mimeParser(typeString); - - // Reject attempts to load JavaScript scripts with a non-default version. - nsAutoString mimeType, version; - if (NS_SUCCEEDED(mimeParser.GetType(mimeType)) && - nsContentUtils::IsJavascriptMIMEType(mimeType) && - NS_SUCCEEDED(mimeParser.GetParameter("version", version))) { - *aShouldLoad = nsIContentPolicy::REJECT_REQUEST; - - LogMessage(NS_MULTILINE_LITERAL_STRING(VERSIONED_JS_BLOCKED_MESSAGE), - aRequestOrigin, typeString, aContext); - return NS_OK; - } - } - - return NS_OK; -} - -NS_IMETHODIMP -AddonContentPolicy::ShouldProcess(uint32_t aContentType, - nsIURI* aContentLocation, - nsIURI* aRequestOrigin, - nsISupports* aRequestingContext, - const nsACString& aMimeTypeGuess, - nsISupports* aExtra, - nsIPrincipal* aRequestPrincipal, - int16_t* aShouldProcess) -{ - MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), - "We should only see external content policy types here."); - - *aShouldProcess = nsIContentPolicy::ACCEPT; - return NS_OK; -} - - -// CSP Validation: - -static const char* allowedSchemes[] = { - "blob", - "filesystem", - nullptr -}; - -static const char* allowedHostSchemes[] = { - "https", - "moz-extension", - nullptr -}; - -/** - * Validates a CSP directive to ensure that it is sufficiently stringent. - * In particular, ensures that: - * - * - No remote sources are allowed other than from https: schemes - * - * - No remote sources specify host wildcards for generic domains - * (*.blogspot.com, *.com, *) - * - * - All remote sources and local extension sources specify a host - * - * - No scheme sources are allowed other than blob:, filesystem:, - * moz-extension:, and https: - * - * - No keyword sources are allowed other than 'none', 'self', 'unsafe-eval', - * and hash sources. - */ -class CSPValidator final : public nsCSPSrcVisitor { - public: - CSPValidator(nsAString& aURL, CSPDirective aDirective, bool aDirectiveRequired = true) : - mURL(aURL), - mDirective(CSP_CSPDirectiveToString(aDirective)), - mFoundSelf(false) - { - // Start with the default error message for a missing directive, since no - // visitors will be called if the directive isn't present. - if (aDirectiveRequired) { - FormatError("csp.error.missing-directive"); - } - } - - // Visitors - - bool visitSchemeSrc(const nsCSPSchemeSrc& src) override - { - nsAutoString scheme; - src.getScheme(scheme); - - if (SchemeInList(scheme, allowedHostSchemes)) { - FormatError("csp.error.missing-host", scheme); - return false; - } - if (!SchemeInList(scheme, allowedSchemes)) { - FormatError("csp.error.illegal-protocol", scheme); - return false; - } - return true; - }; - - bool visitHostSrc(const nsCSPHostSrc& src) override - { - nsAutoString scheme, host; - - src.getScheme(scheme); - src.getHost(host); - - if (scheme.LowerCaseEqualsLiteral("https")) { - if (!HostIsAllowed(host)) { - FormatError("csp.error.illegal-host-wildcard", scheme); - return false; - } - } else if (scheme.LowerCaseEqualsLiteral("moz-extension")) { - // The CSP parser silently converts 'self' keywords to the origin - // URL, so we need to reconstruct the URL to see if it was present. - if (!mFoundSelf) { - nsAutoString url(u"moz-extension://"); - url.Append(host); - - mFoundSelf = url.Equals(mURL); - } - - if (host.IsEmpty() || host.EqualsLiteral("*")) { - FormatError("csp.error.missing-host", scheme); - return false; - } - } else if (!SchemeInList(scheme, allowedSchemes)) { - FormatError("csp.error.illegal-protocol", scheme); - return false; - } - - return true; - }; - - bool visitKeywordSrc(const nsCSPKeywordSrc& src) override - { - switch (src.getKeyword()) { - case CSP_NONE: - case CSP_SELF: - case CSP_UNSAFE_EVAL: - return true; - - default: - NS_ConvertASCIItoUTF16 keyword(CSP_EnumToKeyword(src.getKeyword())); - - FormatError("csp.error.illegal-keyword", keyword); - return false; - } - }; - - bool visitNonceSrc(const nsCSPNonceSrc& src) override - { - FormatError("csp.error.illegal-keyword", NS_LITERAL_STRING("'nonce-*'")); - return false; - }; - - bool visitHashSrc(const nsCSPHashSrc& src) override - { - return true; - }; - - // Accessors - - inline nsAString& GetError() - { - return mError; - }; - - inline bool FoundSelf() - { - return mFoundSelf; - }; - - - // Formatters - - template - inline void FormatError(const char* aName, const T ...aParams) - { - const char16_t* params[] = { mDirective.get(), aParams.get()... }; - FormatErrorParams(aName, params, MOZ_ARRAY_LENGTH(params)); - }; - - private: - // Validators - - bool HostIsAllowed(nsAString& host) - { - if (host.First() == '*') { - if (host.EqualsLiteral("*") || host[1] != '.') { - return false; - } - - host.Cut(0, 2); - - nsCOMPtr tldService = - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); - - if (!tldService) { - return false; - } - - NS_ConvertUTF16toUTF8 cHost(host); - nsAutoCString publicSuffix; - - nsresult rv = tldService->GetPublicSuffixFromHost(cHost, publicSuffix); - - return NS_SUCCEEDED(rv) && !cHost.Equals(publicSuffix); - } - - return true; - }; - - bool SchemeInList(nsAString& scheme, const char** schemes) - { - for (; *schemes; schemes++) { - if (scheme.LowerCaseEqualsASCII(*schemes)) { - return true; - } - } - return false; - }; - - - // Formatters - - already_AddRefed - GetStringBundle() - { - nsCOMPtr sbs = - mozilla::services::GetStringBundleService(); - NS_ENSURE_TRUE(sbs, nullptr); - - nsCOMPtr stringBundle; - sbs->CreateBundle("chrome://global/locale/extensions.properties", - getter_AddRefs(stringBundle)); - - return stringBundle.forget(); - }; - - void FormatErrorParams(const char* aName, const char16_t** aParams, int32_t aLength) - { - nsresult rv = NS_ERROR_FAILURE; - - nsCOMPtr stringBundle = GetStringBundle(); - - if (stringBundle) { - NS_ConvertASCIItoUTF16 name(aName); - - rv = stringBundle->FormatStringFromName(name.get(), aParams, aLength, - getter_Copies(mError)); - } - - if (NS_WARN_IF(NS_FAILED(rv))) { - mError.AssignLiteral("An unexpected error occurred"); - } - }; - - - // Data members - - nsAutoString mURL; - NS_ConvertASCIItoUTF16 mDirective; - nsXPIDLString mError; - - bool mFoundSelf; -}; - -/** - * Validates a custom content security policy string for use by an add-on. - * In particular, ensures that: - * - * - Both object-src and script-src directives are present, and meet - * the policies required by the CSPValidator class - * - * - The script-src directive includes the source 'self' - */ -NS_IMETHODIMP -AddonContentPolicy::ValidateAddonCSP(const nsAString& aPolicyString, - nsAString& aResult) -{ - nsresult rv; - - // Validate against a randomly-generated extension origin. - // There is no add-on-specific behavior in the CSP code, beyond the ability - // for add-ons to specify a custom policy, but the parser requires a valid - // origin in order to operate correctly. - nsAutoString url(u"moz-extension://"); - { - nsCOMPtr uuidgen = services::GetUUIDGenerator(); - NS_ENSURE_TRUE(uuidgen, NS_ERROR_FAILURE); - - nsID id; - rv = uuidgen->GenerateUUIDInPlace(&id); - NS_ENSURE_SUCCESS(rv, rv); - - char idString[NSID_LENGTH]; - id.ToProvidedString(idString); - - MOZ_RELEASE_ASSERT(idString[0] == '{' && idString[NSID_LENGTH - 2] == '}', - "UUID generator did not return a valid UUID"); - - url.AppendASCII(idString + 1, NSID_LENGTH - 3); - } - - - RefPtr principal = - BasePrincipal::CreateCodebasePrincipal(NS_ConvertUTF16toUTF8(url)); - - nsCOMPtr csp; - rv = principal->EnsureCSP(nullptr, getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv, rv); - - - csp->AppendPolicy(aPolicyString, false, false); - - const nsCSPPolicy* policy = csp->GetPolicy(0); - if (!policy) { - CSPValidator validator(url, nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE); - aResult.Assign(validator.GetError()); - return NS_OK; - } - - bool haveValidDefaultSrc = false; - { - CSPDirective directive = nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE; - CSPValidator validator(url, directive); - - haveValidDefaultSrc = policy->visitDirectiveSrcs(directive, &validator); - } - - aResult.SetIsVoid(true); - { - CSPDirective directive = nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE; - CSPValidator validator(url, directive, !haveValidDefaultSrc); - - if (!policy->visitDirectiveSrcs(directive, &validator)) { - aResult.Assign(validator.GetError()); - } else if (!validator.FoundSelf()) { - validator.FormatError("csp.error.missing-source", NS_LITERAL_STRING("'self'")); - aResult.Assign(validator.GetError()); - } - } - - if (aResult.IsVoid()) { - CSPDirective directive = nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE; - CSPValidator validator(url, directive, !haveValidDefaultSrc); - - if (!policy->visitDirectiveSrcs(directive, &validator)) { - aResult.Assign(validator.GetError()); - } - } - - return NS_OK; -} diff --git a/toolkit/mozapps/extensions/AddonContentPolicy.h b/toolkit/mozapps/extensions/AddonContentPolicy.h deleted file mode 100644 index 4c8af4828..000000000 --- a/toolkit/mozapps/extensions/AddonContentPolicy.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIContentPolicy.h" -#include "nsIAddonPolicyService.h" - -class AddonContentPolicy : public nsIContentPolicy, - public nsIAddonContentPolicy -{ -protected: - virtual ~AddonContentPolicy(); - -public: - AddonContentPolicy(); - - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPOLICY - NS_DECL_NSIADDONCONTENTPOLICY -}; diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm deleted file mode 100644 index c5cb80091..000000000 --- a/toolkit/mozapps/extensions/AddonManager.jsm +++ /dev/null @@ -1,3674 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -// Cannot use Services.appinfo here, or else xpcshell-tests will blow up, as -// most tests later register different nsIAppInfo implementations, which -// wouldn't be reflected in Services.appinfo anymore, as the lazy getter -// underlying it would have been initialized if we used it here. -if ("@mozilla.org/xre/app-info;1" in Cc) { - let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); - if (runtime.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { - // Refuse to run in child processes. - throw new Error("You cannot use the AddonManager in child processes!"); - } -} - -Cu.import("resource://gre/modules/AppConstants.jsm"); - -const MOZ_COMPATIBILITY_NIGHTLY = !['aurora', 'beta', 'release', 'esr'].includes(AppConstants.MOZ_UPDATE_CHANNEL); - -const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion"; -const PREF_DEFAULT_PROVIDERS_ENABLED = "extensions.defaultProviders.enabled"; -const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; -const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; -const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion"; -const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; -const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility"; -const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; -const PREF_EM_UPDATE_BACKGROUND_URL = "extensions.update.background.url"; -const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; -const PREF_APP_UPDATE_AUTO = "app.update.auto"; -const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; -const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion"; -const PREF_EM_HOTFIX_URL = "extensions.hotfix.url"; -const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes"; -const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs."; -const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; -const PREF_SELECTED_LOCALE = "general.useragent.locale"; -const UNKNOWN_XPCOM_ABI = "unknownABI"; - -const PREF_MIN_WEBEXT_PLATFORM_VERSION = "extensions.webExtensionsMinPlatformVersion"; -const PREF_WEBAPI_TESTING = "extensions.webapi.testing"; - -const UPDATE_REQUEST_VERSION = 2; -const CATEGORY_UPDATE_PARAMS = "extension-update-params"; - -const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist"; - -const KEY_PROFILEDIR = "ProfD"; -const KEY_APPDIR = "XCurProcD"; -const FILE_BLOCKLIST = "blocklist.xml"; - -const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; -const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility"; -var PREF_EM_CHECK_COMPATIBILITY = MOZ_COMPATIBILITY_NIGHTLY ? - PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly" : - undefined; - -const TOOLKIT_ID = "toolkit@mozilla.org"; - -const VALID_TYPES_REGEXP = /^[\w\-]+$/; - -const WEBAPI_INSTALL_HOSTS = ["addons.mozilla.org", "testpilot.firefox.com"]; -const WEBAPI_TEST_INSTALL_HOSTS = [ - "addons.allizom.org", "addons-dev.allizom.org", - "testpilot.stage.mozaws.net", "testpilot.dev.mozaws.net", - "example.com", -]; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/AsyncShutdown.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Task", - "resource://gre/modules/Task.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Promise", - "resource://gre/modules/Promise.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", - "resource://gre/modules/addons/AddonRepository.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Extension", - "resource://gre/modules/Extension.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "CertUtils", function() { - let certUtils = {}; - Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils); - return certUtils; -}); - -const INTEGER = /^[1-9]\d*$/; - -this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ]; - -const CATEGORY_PROVIDER_MODULE = "addon-provider-module"; - -// A list of providers to load by default -const DEFAULT_PROVIDERS = [ - "resource://gre/modules/addons/XPIProvider.jsm", - "resource://gre/modules/LightweightThemeManager.jsm" -]; - -Cu.import("resource://gre/modules/Log.jsm"); -// Configure a logger at the parent 'addons' level to format -// messages for all the modules under addons.* -const PARENT_LOGGER_ID = "addons"; -var parentLogger = Log.repository.getLogger(PARENT_LOGGER_ID); -parentLogger.level = Log.Level.Warn; -var formatter = new Log.BasicFormatter(); -// Set parent logger (and its children) to append to -// the Javascript section of the Browser Console -parentLogger.addAppender(new Log.ConsoleAppender(formatter)); -// Set parent logger (and its children) to -// also append to standard out -parentLogger.addAppender(new Log.DumpAppender(formatter)); - -// Create a new logger (child of 'addons' logger) -// for use by the Addons Manager -const LOGGER_ID = "addons.manager"; -var logger = Log.repository.getLogger(LOGGER_ID); - -// Provide the ability to enable/disable logging -// messages at runtime. -// If the "extensions.logging.enabled" preference is -// missing or 'false', messages at the WARNING and higher -// severity should be logged to the JS console and standard error. -// If "extensions.logging.enabled" is set to 'true', messages -// at DEBUG and higher should go to JS console and standard error. -const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; -const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; - -const UNNAMED_PROVIDER = ""; -function providerName(aProvider) { - return aProvider.name || UNNAMED_PROVIDER; -} - -/** - * Preference listener which listens for a change in the - * "extensions.logging.enabled" preference and changes the logging level of the - * parent 'addons' level logger accordingly. - */ -var PrefObserver = { - init: function() { - Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); - Services.obs.addObserver(this, "xpcom-shutdown", false); - this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); - }, - - observe: function(aSubject, aTopic, aData) { - if (aTopic == "xpcom-shutdown") { - Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); - Services.obs.removeObserver(this, "xpcom-shutdown"); - } - else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { - let debugLogEnabled = false; - try { - debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); - } - catch (e) { - } - if (debugLogEnabled) { - parentLogger.level = Log.Level.Debug; - } - else { - parentLogger.level = Log.Level.Warn; - } - } - } -}; - -PrefObserver.init(); - -/** - * Calls a callback method consuming any thrown exception. Any parameters after - * the callback parameter will be passed to the callback. - * - * @param aCallback - * The callback method to call - */ -function safeCall(aCallback, ...aArgs) { - try { - aCallback.apply(null, aArgs); - } - catch (e) { - logger.warn("Exception calling callback", e); - } -} - -/** - * Creates a function that will call the passed callback catching and logging - * any exceptions. - * - * @param aCallback - * The callback method to call - */ -function makeSafe(aCallback) { - return function(...aArgs) { - safeCall(aCallback, ...aArgs); - } -} - -/** - * Report an exception thrown by a provider API method. - */ -function reportProviderError(aProvider, aMethod, aError) { - let method = `provider ${providerName(aProvider)}.${aMethod}`; - AddonManagerPrivate.recordException("AMI", method, aError); - logger.error("Exception calling " + method, aError); -} - -/** - * Calls a method on a provider if it exists and consumes any thrown exception. - * Any parameters after the aDefault parameter are passed to the provider's method. - * - * @param aProvider - * The provider to call - * @param aMethod - * The method name to call - * @param aDefault - * A default return value if the provider does not implement the named - * method or throws an error. - * @return the return value from the provider, or aDefault if the provider does not - * implement method or throws an error - */ -function callProvider(aProvider, aMethod, aDefault, ...aArgs) { - if (!(aMethod in aProvider)) - return aDefault; - - try { - return aProvider[aMethod].apply(aProvider, aArgs); - } - catch (e) { - reportProviderError(aProvider, aMethod, e); - return aDefault; - } -} - -/** - * Calls a method on a provider if it exists and consumes any thrown exception. - * Parameters after aMethod are passed to aProvider.aMethod(). - * The last parameter must be a callback function. - * If the provider does not implement the method, or the method throws, calls - * the callback with 'undefined'. - * - * @param aProvider - * The provider to call - * @param aMethod - * The method name to call - */ -function callProviderAsync(aProvider, aMethod, ...aArgs) { - let callback = aArgs[aArgs.length - 1]; - if (!(aMethod in aProvider)) { - callback(undefined); - return undefined; - } - try { - return aProvider[aMethod].apply(aProvider, aArgs); - } - catch (e) { - reportProviderError(aProvider, aMethod, e); - callback(undefined); - return undefined; - } -} - -/** - * Calls a method on a provider if it exists and consumes any thrown exception. - * Parameters after aMethod are passed to aProvider.aMethod() and an additional - * callback is added for the provider to return a result to. - * - * @param aProvider - * The provider to call - * @param aMethod - * The method name to call - * @return {Promise} - * @resolves The result the provider returns, or |undefined| if the provider - * does not implement the method or the method throws. - * @rejects Never - */ -function promiseCallProvider(aProvider, aMethod, ...aArgs) { - return new Promise(resolve => { - callProviderAsync(aProvider, aMethod, ...aArgs, resolve); - }); -} - -/** - * Gets the currently selected locale for display. - * @return the selected locale or "en-US" if none is selected - */ -function getLocale() { - try { - if (Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE)) - return Services.locale.getLocaleComponentForUserAgent(); - } - catch (e) { } - - try { - let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE, - Ci.nsIPrefLocalizedString); - if (locale) - return locale; - } - catch (e) { } - - try { - return Services.prefs.getCharPref(PREF_SELECTED_LOCALE); - } - catch (e) { } - - return "en-US"; -} - -function webAPIForAddon(addon) { - if (!addon) { - return null; - } - - let result = {}; - - // By default just pass through any plain property, the webidl will - // control access. Also filter out private properties, regular Addon - // objects are okay but MockAddon used in tests has non-serializable - // private properties. - for (let prop in addon) { - if (prop[0] != "_" && typeof(addon[prop]) != "function") { - result[prop] = addon[prop]; - } - } - - // A few properties are computed for a nicer API - result.isEnabled = !addon.userDisabled; - result.canUninstall = Boolean(addon.permissions & AddonManager.PERM_CAN_UNINSTALL); - - return result; -} - -/** - * A helper class to repeatedly call a listener with each object in an array - * optionally checking whether the object has a method in it. - * - * @param aObjects - * The array of objects to iterate through - * @param aMethod - * An optional method name, if not null any objects without this method - * will not be passed to the listener - * @param aListener - * A listener implementing nextObject and noMoreObjects methods. The - * former will be called with the AsyncObjectCaller as the first - * parameter and the object as the second. noMoreObjects will be passed - * just the AsyncObjectCaller - */ -function AsyncObjectCaller(aObjects, aMethod, aListener) { - this.objects = [...aObjects]; - this.method = aMethod; - this.listener = aListener; - - this.callNext(); -} - -AsyncObjectCaller.prototype = { - objects: null, - method: null, - listener: null, - - /** - * Passes the next object to the listener or calls noMoreObjects if there - * are none left. - */ - callNext: function() { - if (this.objects.length == 0) { - this.listener.noMoreObjects(this); - return; - } - - let object = this.objects.shift(); - if (!this.method || this.method in object) - this.listener.nextObject(this, object); - else - this.callNext(); - } -}; - -/** - * Listens for a browser changing origin and cancels the installs that were - * started by it. - */ -function BrowserListener(aBrowser, aInstallingPrincipal, aInstalls) { - this.browser = aBrowser; - this.principal = aInstallingPrincipal; - this.installs = aInstalls; - this.installCount = aInstalls.length; - - aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); - Services.obs.addObserver(this, "message-manager-close", true); - - for (let install of this.installs) - install.addListener(this); - - this.registered = true; -} - -BrowserListener.prototype = { - browser: null, - installs: null, - installCount: null, - registered: false, - - unregister: function() { - if (!this.registered) - return; - this.registered = false; - - Services.obs.removeObserver(this, "message-manager-close"); - // The browser may have already been detached - if (this.browser.removeProgressListener) - this.browser.removeProgressListener(this); - - for (let install of this.installs) - install.removeListener(this); - this.installs = null; - }, - - cancelInstalls: function() { - for (let install of this.installs) { - try { - install.cancel(); - } - catch (e) { - // Some installs may have already failed or been cancelled, ignore these - } - } - }, - - observe: function(subject, topic, data) { - if (subject != this.browser.messageManager) - return; - - // The browser's message manager has closed and so the browser is - // going away, cancel all installs - this.cancelInstalls(); - }, - - onLocationChange: function(webProgress, request, location) { - if (this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal)) - return; - - // The browser has navigated to a new origin so cancel all installs - this.cancelInstalls(); - }, - - onDownloadCancelled: function(install) { - // Don't need to hear more events from this install - install.removeListener(this); - - // Once all installs have ended unregister everything - if (--this.installCount == 0) - this.unregister(); - }, - - onDownloadFailed: function(install) { - this.onDownloadCancelled(install); - }, - - onInstallFailed: function(install) { - this.onDownloadCancelled(install); - }, - - onInstallEnded: function(install) { - this.onDownloadCancelled(install); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, - Ci.nsIWebProgressListener, - Ci.nsIObserver]) -}; - -/** - * This represents an author of an add-on (e.g. creator or developer) - * - * @param aName - * The name of the author - * @param aURL - * The URL of the author's profile page - */ -function AddonAuthor(aName, aURL) { - this.name = aName; - this.url = aURL; -} - -AddonAuthor.prototype = { - name: null, - url: null, - - // Returns the author's name, defaulting to the empty string - toString: function() { - return this.name || ""; - } -} - -/** - * This represents an screenshot for an add-on - * - * @param aURL - * The URL to the full version of the screenshot - * @param aWidth - * The width in pixels of the screenshot - * @param aHeight - * The height in pixels of the screenshot - * @param aThumbnailURL - * The URL to the thumbnail version of the screenshot - * @param aThumbnailWidth - * The width in pixels of the thumbnail version of the screenshot - * @param aThumbnailHeight - * The height in pixels of the thumbnail version of the screenshot - * @param aCaption - * The caption of the screenshot - */ -function AddonScreenshot(aURL, aWidth, aHeight, aThumbnailURL, - aThumbnailWidth, aThumbnailHeight, aCaption) { - this.url = aURL; - if (aWidth) this.width = aWidth; - if (aHeight) this.height = aHeight; - if (aThumbnailURL) this.thumbnailURL = aThumbnailURL; - if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth; - if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight; - if (aCaption) this.caption = aCaption; -} - -AddonScreenshot.prototype = { - url: null, - width: null, - height: null, - thumbnailURL: null, - thumbnailWidth: null, - thumbnailHeight: null, - caption: null, - - // Returns the screenshot URL, defaulting to the empty string - toString: function() { - return this.url || ""; - } -} - - -/** - * This represents a compatibility override for an addon. - * - * @param aType - * Overrride type - "compatible" or "incompatible" - * @param aMinVersion - * Minimum version of the addon to match - * @param aMaxVersion - * Maximum version of the addon to match - * @param aAppID - * Application ID used to match appMinVersion and appMaxVersion - * @param aAppMinVersion - * Minimum version of the application to match - * @param aAppMaxVersion - * Maximum version of the application to match - */ -function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID, - aAppMinVersion, aAppMaxVersion) { - this.type = aType; - this.minVersion = aMinVersion; - this.maxVersion = aMaxVersion; - this.appID = aAppID; - this.appMinVersion = aAppMinVersion; - this.appMaxVersion = aAppMaxVersion; -} - -AddonCompatibilityOverride.prototype = { - /** - * Type of override - "incompatible" or "compatible". - * Only "incompatible" is supported for now. - */ - type: null, - - /** - * Min version of the addon to match. - */ - minVersion: null, - - /** - * Max version of the addon to match. - */ - maxVersion: null, - - /** - * Application ID to match. - */ - appID: null, - - /** - * Min version of the application to match. - */ - appMinVersion: null, - - /** - * Max version of the application to match. - */ - appMaxVersion: null -}; - - -/** - * A type of add-on, used by the UI to determine how to display different types - * of add-ons. - * - * @param aID - * The add-on type ID - * @param aLocaleURI - * The URI of a localized properties file to get the displayable name - * for the type from - * @param aLocaleKey - * The key for the string in the properties file or the actual display - * name if aLocaleURI is null. Include %ID% to include the type ID in - * the key - * @param aViewType - * The optional type of view to use in the UI - * @param aUIPriority - * The priority is used by the UI to list the types in order. Lower - * values push the type higher in the list. - * @param aFlags - * An option set of flags that customize the display of the add-on in - * the UI. - */ -function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) { - if (!aID) - throw Components.Exception("An AddonType must have an ID", Cr.NS_ERROR_INVALID_ARG); - - if (aViewType && aUIPriority === undefined) - throw Components.Exception("An AddonType with a defined view must have a set UI priority", - Cr.NS_ERROR_INVALID_ARG); - - if (!aLocaleKey) - throw Components.Exception("An AddonType must have a displayable name", - Cr.NS_ERROR_INVALID_ARG); - - this.id = aID; - this.uiPriority = aUIPriority; - this.viewType = aViewType; - this.flags = aFlags; - - if (aLocaleURI) { - XPCOMUtils.defineLazyGetter(this, "name", () => { - let bundle = Services.strings.createBundle(aLocaleURI); - return bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID)); - }); - } - else { - this.name = aLocaleKey; - } -} - -var gStarted = false; -var gStartupComplete = false; -var gCheckCompatibility = true; -var gStrictCompatibility = true; -var gCheckUpdateSecurityDefault = true; -var gCheckUpdateSecurity = gCheckUpdateSecurityDefault; -var gUpdateEnabled = true; -var gAutoUpdateDefault = true; -var gHotfixID = null; -var gWebExtensionsMinPlatformVersion = null; -var gShutdownBarrier = null; -var gRepoShutdownState = ""; -var gShutdownInProgress = false; -var gPluginPageListener = null; - -/** - * This is the real manager, kept here rather than in AddonManager to keep its - * contents hidden from API users. - */ -var AddonManagerInternal = { - managerListeners: [], - installListeners: [], - addonListeners: [], - typeListeners: [], - pendingProviders: new Set(), - providers: new Set(), - providerShutdowns: new Map(), - types: {}, - startupChanges: {}, - // Store telemetry details per addon provider - telemetryDetails: {}, - upgradeListeners: new Map(), - - recordTimestamp: function(name, value) { - this.TelemetryTimestamps.add(name, value); - }, - - validateBlocklist: function() { - let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]); - - // If there is no application shipped blocklist then there is nothing to do - if (!appBlocklist.exists()) - return; - - let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]); - - // If there is no blocklist in the profile then copy the application shipped - // one there - if (!profileBlocklist.exists()) { - try { - appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); - } - catch (e) { - logger.warn("Failed to copy the application shipped blocklist to the profile", e); - } - return; - } - - let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - try { - let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]. - createInstance(Ci.nsIConverterInputStream); - fileStream.init(appBlocklist, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); - cstream.init(fileStream, "UTF-8", 0, 0); - - let data = ""; - let str = {}; - let read = 0; - do { - read = cstream.readString(0xffffffff, str); - data += str.value; - } while (read != 0); - - let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(Ci.nsIDOMParser); - var doc = parser.parseFromString(data, "text/xml"); - } - catch (e) { - logger.warn("Application shipped blocklist could not be loaded", e); - return; - } - finally { - try { - fileStream.close(); - } - catch (e) { - logger.warn("Unable to close blocklist file stream", e); - } - } - - // If the namespace is incorrect then ignore the application shipped - // blocklist - if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) { - logger.warn("Application shipped blocklist has an unexpected namespace (" + - doc.documentElement.namespaceURI + ")"); - return; - } - - // If there is no lastupdate information then ignore the application shipped - // blocklist - if (!doc.documentElement.hasAttribute("lastupdate")) - return; - - // If the application shipped blocklist is older than the profile blocklist - // then do nothing - if (doc.documentElement.getAttribute("lastupdate") <= - profileBlocklist.lastModifiedTime) - return; - - // Otherwise copy the application shipped blocklist to the profile - try { - appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); - } - catch (e) { - logger.warn("Failed to copy the application shipped blocklist to the profile", e); - } - }, - - /** - * Start up a provider, and register its shutdown hook if it has one - */ - _startProvider(aProvider, aAppChanged, aOldAppVersion, aOldPlatformVersion) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - logger.debug(`Starting provider: ${providerName(aProvider)}`); - callProvider(aProvider, "startup", null, aAppChanged, aOldAppVersion, aOldPlatformVersion); - if ('shutdown' in aProvider) { - let name = providerName(aProvider); - let AMProviderShutdown = () => { - // If the provider has been unregistered, it will have been removed from - // this.providers. If it hasn't been unregistered, then this is a normal - // shutdown - and we move it to this.pendingProviders incase we're - // running in a test that will start AddonManager again. - if (this.providers.has(aProvider)) { - this.providers.delete(aProvider); - this.pendingProviders.add(aProvider); - } - - return new Promise((resolve, reject) => { - logger.debug("Calling shutdown blocker for " + name); - resolve(aProvider.shutdown()); - }) - .catch(err => { - logger.warn("Failure during shutdown of " + name, err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of " + name, err); - }); - }; - logger.debug("Registering shutdown blocker for " + name); - this.providerShutdowns.set(aProvider, AMProviderShutdown); - AddonManager.shutdown.addBlocker(name, AMProviderShutdown); - } - - this.pendingProviders.delete(aProvider); - this.providers.add(aProvider); - logger.debug(`Provider finished startup: ${providerName(aProvider)}`); - }, - - _getProviderByName(aName) { - for (let provider of this.providers) { - if (providerName(provider) == aName) - return provider; - } - return undefined; - }, - - /** - * Initializes the AddonManager, loading any known providers and initializing - * them. - */ - startup: function() { - try { - if (gStarted) - return; - - this.recordTimestamp("AMI_startup_begin"); - - // clear this for xpcshell test restarts - for (let provider in this.telemetryDetails) - delete this.telemetryDetails[provider]; - - let appChanged = undefined; - - let oldAppVersion = null; - try { - oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); - appChanged = Services.appinfo.version != oldAppVersion; - } - catch (e) { } - - Extension.browserUpdated = appChanged; - - let oldPlatformVersion = null; - try { - oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION); - } - catch (e) { } - - if (appChanged !== false) { - logger.debug("Application has been upgraded"); - Services.prefs.setCharPref(PREF_EM_LAST_APP_VERSION, - Services.appinfo.version); - Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION, - Services.appinfo.platformVersion); - Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, - (appChanged === undefined ? 0 : -1)); - this.validateBlocklist(); - } - - if (!MOZ_COMPATIBILITY_NIGHTLY) { - PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." + - Services.appinfo.version.replace(BRANCH_REGEXP, "$1"); - } - - try { - gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_CHECK_COMPATIBILITY, this, false); - - try { - gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_STRICT_COMPATIBILITY, this, false); - - try { - let defaultBranch = Services.prefs.getDefaultBranch(""); - gCheckUpdateSecurityDefault = defaultBranch.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); - } catch (e) {} - - try { - gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_CHECK_UPDATE_SECURITY, this, false); - - try { - gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_UPDATE_ENABLED, this, false); - - try { - gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false); - - try { - gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); - } catch (e) {} - Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false); - - try { - gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION); - } catch (e) {} - Services.prefs.addObserver(PREF_MIN_WEBEXT_PLATFORM_VERSION, this, false); - - let defaultProvidersEnabled = true; - try { - defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED); - } catch (e) {} - AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled); - - // Ensure all default providers have had a chance to register themselves - if (defaultProvidersEnabled) { - for (let url of DEFAULT_PROVIDERS) { - try { - let scope = {}; - Components.utils.import(url, scope); - // Sanity check - make sure the provider exports a symbol that - // has a 'startup' method - let syms = Object.keys(scope); - if ((syms.length < 1) || - (typeof scope[syms[0]].startup != "function")) { - logger.warn("Provider " + url + " has no startup()"); - AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()"); - } - logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource()); - } - catch (e) { - AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); - logger.error("Exception loading default provider \"" + url + "\"", e); - } - } - } - - // Load any providers registered in the category manager - let catman = Cc["@mozilla.org/categorymanager;1"]. - getService(Ci.nsICategoryManager); - let entries = catman.enumerateCategory(CATEGORY_PROVIDER_MODULE); - while (entries.hasMoreElements()) { - let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; - let url = catman.getCategoryEntry(CATEGORY_PROVIDER_MODULE, entry); - - try { - Components.utils.import(url, {}); - logger.debug(`Loaded provider scope for ${url}`); - } - catch (e) { - AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); - logger.error("Exception loading provider " + entry + " from category \"" + - url + "\"", e); - } - } - - // Register our shutdown handler with the AsyncShutdown manager - gShutdownBarrier = new AsyncShutdown.Barrier("AddonManager: Waiting for providers to shut down."); - AsyncShutdown.profileBeforeChange.addBlocker("AddonManager: shutting down.", - this.shutdownManager.bind(this), - {fetchState: this.shutdownState.bind(this)}); - - // Once we start calling providers we must allow all normal methods to work. - gStarted = true; - - for (let provider of this.pendingProviders) { - this._startProvider(provider, appChanged, oldAppVersion, oldPlatformVersion); - } - - // If this is a new profile just pretend that there were no changes - if (appChanged === undefined) { - for (let type in this.startupChanges) - delete this.startupChanges[type]; - } - - // Support for remote about:plugins. Note that this module isn't loaded - // at the top because Services.appinfo is defined late in tests. - let { RemotePages } = Cu.import("resource://gre/modules/RemotePageManager.jsm", {}); - - gPluginPageListener = new RemotePages("about:plugins"); - gPluginPageListener.addMessageListener("RequestPlugins", this.requestPlugins); - - gStartupComplete = true; - this.recordTimestamp("AMI_startup_end"); - } - catch (e) { - logger.error("startup failed", e); - AddonManagerPrivate.recordException("AMI", "startup failed", e); - } - - logger.debug("Completed startup sequence"); - this.callManagerListeners("onStartup"); - }, - - /** - * Registers a new AddonProvider. - * - * @param aProvider - * The provider to register - * @param aTypes - * An optional array of add-on types - */ - registerProvider: function(aProvider, aTypes) { - if (!aProvider || typeof aProvider != "object") - throw Components.Exception("aProvider must be specified", - Cr.NS_ERROR_INVALID_ARG); - - if (aTypes && !Array.isArray(aTypes)) - throw Components.Exception("aTypes must be an array or null", - Cr.NS_ERROR_INVALID_ARG); - - this.pendingProviders.add(aProvider); - - if (aTypes) { - for (let type of aTypes) { - if (!(type.id in this.types)) { - if (!VALID_TYPES_REGEXP.test(type.id)) { - logger.warn("Ignoring invalid type " + type.id); - return; - } - - this.types[type.id] = { - type: type, - providers: [aProvider] - }; - - let typeListeners = this.typeListeners.slice(0); - for (let listener of typeListeners) - safeCall(() => listener.onTypeAdded(type)); - } - else { - this.types[type.id].providers.push(aProvider); - } - } - } - - // If we're registering after startup call this provider's startup. - if (gStarted) { - this._startProvider(aProvider); - } - }, - - /** - * Unregisters an AddonProvider. - * - * @param aProvider - * The provider to unregister - * @return Whatever the provider's 'shutdown' method returns (if anything). - * For providers that have async shutdown methods returning Promises, - * the caller should wait for that Promise to resolve. - */ - unregisterProvider: function(aProvider) { - if (!aProvider || typeof aProvider != "object") - throw Components.Exception("aProvider must be specified", - Cr.NS_ERROR_INVALID_ARG); - - this.providers.delete(aProvider); - // The test harness will unregister XPIProvider *after* shutdown, which is - // after the provider will have been moved from providers to - // pendingProviders. - this.pendingProviders.delete(aProvider); - - for (let type in this.types) { - this.types[type].providers = this.types[type].providers.filter(p => p != aProvider); - if (this.types[type].providers.length == 0) { - let oldType = this.types[type].type; - delete this.types[type]; - - let typeListeners = this.typeListeners.slice(0); - for (let listener of typeListeners) - safeCall(() => listener.onTypeRemoved(oldType)); - } - } - - // If we're unregistering after startup but before shutting down, - // remove the blocker for this provider's shutdown and call it. - // If we're already shutting down, just let gShutdownBarrier call it to avoid races. - if (gStarted && !gShutdownInProgress) { - logger.debug("Unregistering shutdown blocker for " + providerName(aProvider)); - let shutter = this.providerShutdowns.get(aProvider); - if (shutter) { - this.providerShutdowns.delete(aProvider); - gShutdownBarrier.client.removeBlocker(shutter); - return shutter(); - } - } - return undefined; - }, - - /** - * Mark a provider as safe to access via AddonManager APIs, before its - * startup has completed. - * - * Normally a provider isn't marked as safe until after its (synchronous) - * startup() method has returned. Until a provider has been marked safe, - * it won't be used by any of the AddonManager APIs. markProviderSafe() - * allows a provider to mark itself as safe during its startup; this can be - * useful if the provider wants to perform tasks that block startup, which - * happen after its required initialization tasks and therefore when the - * provider is in a safe state. - * - * @param aProvider Provider object to mark safe - */ - markProviderSafe: function(aProvider) { - if (!gStarted) { - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - } - - if (!aProvider || typeof aProvider != "object") { - throw Components.Exception("aProvider must be specified", - Cr.NS_ERROR_INVALID_ARG); - } - - if (!this.pendingProviders.has(aProvider)) { - return; - } - - this.pendingProviders.delete(aProvider); - this.providers.add(aProvider); - }, - - /** - * Calls a method on all registered providers if it exists and consumes any - * thrown exception. Return values are ignored. Any parameters after the - * method parameter are passed to the provider's method. - * WARNING: Do not use for asynchronous calls; callProviders() does not - * invoke callbacks if provider methods throw synchronous exceptions. - * - * @param aMethod - * The method name to call - * @see callProvider - */ - callProviders: function(aMethod, ...aArgs) { - if (!aMethod || typeof aMethod != "string") - throw Components.Exception("aMethod must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - let providers = [...this.providers]; - for (let provider of providers) { - try { - if (aMethod in provider) - provider[aMethod].apply(provider, aArgs); - } - catch (e) { - reportProviderError(provider, aMethod, e); - } - } - }, - - /** - * Report the current state of asynchronous shutdown - */ - shutdownState() { - let state = []; - if (gShutdownBarrier) { - state.push({ - name: gShutdownBarrier.client.name, - state: gShutdownBarrier.state - }); - } - state.push({ - name: "AddonRepository: async shutdown", - state: gRepoShutdownState - }); - return state; - }, - - /** - * Shuts down the addon manager and all registered providers, this must clean - * up everything in order for automated tests to fake restarts. - * @return Promise{null} that resolves when all providers and dependent modules - * have finished shutting down - */ - shutdownManager: Task.async(function*() { - logger.debug("shutdown"); - this.callManagerListeners("onShutdown"); - - gRepoShutdownState = "pending"; - gShutdownInProgress = true; - // Clean up listeners - Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this); - Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this); - Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this); - Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this); - Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this); - Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this); - gPluginPageListener.destroy(); - gPluginPageListener = null; - - let savedError = null; - // Only shut down providers if they've been started. - if (gStarted) { - try { - yield gShutdownBarrier.wait(); - } - catch (err) { - savedError = err; - logger.error("Failure during wait for shutdown barrier", err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonManager providers", err); - } - } - - // Shut down AddonRepository after providers (if any). - try { - gRepoShutdownState = "in progress"; - yield AddonRepository.shutdown(); - gRepoShutdownState = "done"; - } - catch (err) { - savedError = err; - logger.error("Failure during AddonRepository shutdown", err); - AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonRepository", err); - } - - logger.debug("Async provider shutdown done"); - this.managerListeners.splice(0, this.managerListeners.length); - this.installListeners.splice(0, this.installListeners.length); - this.addonListeners.splice(0, this.addonListeners.length); - this.typeListeners.splice(0, this.typeListeners.length); - this.providerShutdowns.clear(); - for (let type in this.startupChanges) - delete this.startupChanges[type]; - gStarted = false; - gStartupComplete = false; - gShutdownBarrier = null; - gShutdownInProgress = false; - if (savedError) { - throw savedError; - } - }), - - requestPlugins: function({ target: port }) { - // Lists all the properties that plugins.html needs - const NEEDED_PROPS = ["name", "pluginLibraries", "pluginFullpath", "version", - "isActive", "blocklistState", "description", - "pluginMimeTypes"]; - function filterProperties(plugin) { - let filtered = {}; - for (let prop of NEEDED_PROPS) { - filtered[prop] = plugin[prop]; - } - return filtered; - } - - AddonManager.getAddonsByTypes(["plugin"], function(aPlugins) { - port.sendAsyncMessage("PluginList", aPlugins.map(filterProperties)); - }); - }, - - /** - * Notified when a preference we're interested in has changed. - * - * @see nsIObserver - */ - observe: function(aSubject, aTopic, aData) { - switch (aData) { - case PREF_EM_CHECK_COMPATIBILITY: { - let oldValue = gCheckCompatibility; - try { - gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); - } catch (e) { - gCheckCompatibility = true; - } - - this.callManagerListeners("onCompatibilityModeChanged"); - - if (gCheckCompatibility != oldValue) - this.updateAddonAppDisabledStates(); - - break; - } - case PREF_EM_STRICT_COMPATIBILITY: { - let oldValue = gStrictCompatibility; - try { - gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); - } catch (e) { - gStrictCompatibility = true; - } - - this.callManagerListeners("onCompatibilityModeChanged"); - - if (gStrictCompatibility != oldValue) - this.updateAddonAppDisabledStates(); - - break; - } - case PREF_EM_CHECK_UPDATE_SECURITY: { - let oldValue = gCheckUpdateSecurity; - try { - gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); - } catch (e) { - gCheckUpdateSecurity = true; - } - - this.callManagerListeners("onCheckUpdateSecurityChanged"); - - if (gCheckUpdateSecurity != oldValue) - this.updateAddonAppDisabledStates(); - - break; - } - case PREF_EM_UPDATE_ENABLED: { - let oldValue = gUpdateEnabled; - try { - gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); - } catch (e) { - gUpdateEnabled = true; - } - - this.callManagerListeners("onUpdateModeChanged"); - break; - } - case PREF_EM_AUTOUPDATE_DEFAULT: { - let oldValue = gAutoUpdateDefault; - try { - gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); - } catch (e) { - gAutoUpdateDefault = true; - } - - this.callManagerListeners("onUpdateModeChanged"); - break; - } - case PREF_EM_HOTFIX_ID: { - try { - gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); - } catch (e) { - gHotfixID = null; - } - break; - } - case PREF_MIN_WEBEXT_PLATFORM_VERSION: { - gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION); - break; - } - } - }, - - /** - * Replaces %...% strings in an addon url (update and updateInfo) with - * appropriate values. - * - * @param aAddon - * The Addon representing the add-on - * @param aUri - * The string representation of the URI to escape - * @param aAppVersion - * The optional application version to use for %APP_VERSION% - * @return The appropriately escaped URI. - */ - escapeAddonURI: function(aAddon, aUri, aAppVersion) - { - if (!aAddon || typeof aAddon != "object") - throw Components.Exception("aAddon must be an Addon object", - Cr.NS_ERROR_INVALID_ARG); - - if (!aUri || typeof aUri != "string") - throw Components.Exception("aUri must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (aAppVersion && typeof aAppVersion != "string") - throw Components.Exception("aAppVersion must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled" - : "userEnabled"; - - if (!aAddon.isCompatible) - addonStatus += ",incompatible"; - if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) - addonStatus += ",blocklisted"; - if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) - addonStatus += ",softblocked"; - - try { - var xpcomABI = Services.appinfo.XPCOMABI; - } catch (ex) { - xpcomABI = UNKNOWN_XPCOM_ABI; - } - - let uri = aUri.replace(/%ITEM_ID%/g, aAddon.id); - uri = uri.replace(/%ITEM_VERSION%/g, aAddon.version); - uri = uri.replace(/%ITEM_STATUS%/g, addonStatus); - uri = uri.replace(/%APP_ID%/g, Services.appinfo.ID); - uri = uri.replace(/%APP_VERSION%/g, aAppVersion ? aAppVersion : - Services.appinfo.version); - uri = uri.replace(/%REQ_VERSION%/g, UPDATE_REQUEST_VERSION); - uri = uri.replace(/%APP_OS%/g, Services.appinfo.OS); - uri = uri.replace(/%APP_ABI%/g, xpcomABI); - uri = uri.replace(/%APP_LOCALE%/g, getLocale()); - uri = uri.replace(/%CURRENT_APP_VERSION%/g, Services.appinfo.version); - - // Replace custom parameters (names of custom parameters must have at - // least 3 characters to prevent lookups for something like %D0%C8) - var catMan = null; - uri = uri.replace(/%(\w{3,})%/g, function(aMatch, aParam) { - if (!catMan) { - catMan = Cc["@mozilla.org/categorymanager;1"]. - getService(Ci.nsICategoryManager); - } - - try { - var contractID = catMan.getCategoryEntry(CATEGORY_UPDATE_PARAMS, aParam); - var paramHandler = Cc[contractID].getService(Ci.nsIPropertyBag2); - return paramHandler.getPropertyAsAString(aParam); - } - catch (e) { - return aMatch; - } - }); - - // escape() does not properly encode + symbols in any embedded FVF strings. - return uri.replace(/\+/g, "%2B"); - }, - - /** - * Performs a background update check by starting an update for all add-ons - * that can be updated. - * @return Promise{null} Resolves when the background update check is complete - * (the resulting addon installations may still be in progress). - */ - backgroundUpdateCheck: function() { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - let buPromise = Task.spawn(function*() { - let hotfixID = this.hotfixID; - - let appUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && - Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); - let checkHotfix = hotfixID && appUpdateEnabled; - - logger.debug("Background update check beginning"); - - Services.obs.notifyObservers(null, "addons-background-update-start", null); - - if (this.updateEnabled) { - let scope = {}; - Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope); - scope.LightweightThemeManager.updateCurrentTheme(); - - let allAddons = yield new Promise((resolve, reject) => this.getAllAddons(resolve)); - - // Repopulate repository cache first, to ensure compatibility overrides - // are up to date before checking for addon updates. - yield AddonRepository.backgroundUpdateCheck(); - - // Keep track of all the async add-on updates happening in parallel - let updates = []; - - for (let addon of allAddons) { - if (addon.id == hotfixID) { - continue; - } - - // Check all add-ons for updates so that any compatibility updates will - // be applied - updates.push(new Promise((resolve, reject) => { - addon.findUpdates({ - onUpdateAvailable: function(aAddon, aInstall) { - // Start installing updates when the add-on can be updated and - // background updates should be applied. - logger.debug("Found update for add-on ${id}", aAddon); - if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE && - AddonManager.shouldAutoUpdate(aAddon)) { - // XXX we really should resolve when this install is done, - // not when update-available check completes, no? - logger.debug(`Starting upgrade install of ${aAddon.id}`); - aInstall.install(); - } - }, - - onUpdateFinished: aAddon => { logger.debug("onUpdateFinished for ${id}", aAddon); resolve(); } - }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE); - })); - } - yield Promise.all(updates); - } - - if (checkHotfix) { - var hotfixVersion = ""; - try { - hotfixVersion = Services.prefs.getCharPref(PREF_EM_HOTFIX_LASTVERSION); - } - catch (e) { } - - let url = null; - if (Services.prefs.getPrefType(PREF_EM_HOTFIX_URL) == Ci.nsIPrefBranch.PREF_STRING) - url = Services.prefs.getCharPref(PREF_EM_HOTFIX_URL); - else - url = Services.prefs.getCharPref(PREF_EM_UPDATE_BACKGROUND_URL); - - // Build the URI from a fake add-on data. - url = AddonManager.escapeAddonURI({ - id: hotfixID, - version: hotfixVersion, - userDisabled: false, - appDisabled: false - }, url); - - Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm"); - let update = null; - try { - let foundUpdates = yield new Promise((resolve, reject) => { - AddonUpdateChecker.checkForUpdates(hotfixID, null, url, { - onUpdateCheckComplete: resolve, - onUpdateCheckError: reject - }); - }); - update = AddonUpdateChecker.getNewestCompatibleUpdate(foundUpdates); - } catch (e) { - // AUC.checkForUpdates already logged the error - } - - // Check that we have a hotfix update, and it's newer than the one we already - // have installed (if any) - if (update) { - if (Services.vc.compare(hotfixVersion, update.version) < 0) { - logger.debug("Downloading hotfix version " + update.version); - let aInstall = yield new Promise((resolve, reject) => - AddonManager.getInstallForURL(update.updateURL, resolve, - "application/x-xpinstall", update.updateHash, null, - null, update.version)); - - aInstall.addListener({ - onDownloadEnded: function(aInstall) { - if (aInstall.addon.id != hotfixID) { - logger.warn("The downloaded hotfix add-on did not have the " + - "expected ID and so will not be installed."); - aInstall.cancel(); - return; - } - - // If XPIProvider has reported the hotfix as properly signed then - // there is nothing more to do here - if (aInstall.addon.signedState == AddonManager.SIGNEDSTATE_SIGNED) - return; - - try { - if (!Services.prefs.getBoolPref(PREF_EM_CERT_CHECKATTRIBUTES)) - return; - } - catch (e) { - // By default don't do certificate checks. - return; - } - - try { - CertUtils.validateCert(aInstall.certificate, - CertUtils.readCertPrefs(PREF_EM_HOTFIX_CERTS)); - } - catch (e) { - logger.warn("The hotfix add-on was not signed by the expected " + - "certificate and so will not be installed.", e); - aInstall.cancel(); - } - }, - - onInstallEnded: function(aInstall) { - // Remember the last successfully installed version. - Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, - aInstall.version); - }, - - onInstallCancelled: function(aInstall) { - // Revert to the previous version if the installation was - // cancelled. - Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, - hotfixVersion); - } - }); - - aInstall.install(); - } - } - } - - if (appUpdateEnabled) { - try { - yield AddonManagerInternal._getProviderByName("XPIProvider").updateSystemAddons(); - } - catch (e) { - logger.warn("Failed to update system addons", e); - } - } - - logger.debug("Background update check complete"); - Services.obs.notifyObservers(null, - "addons-background-update-complete", - null); - }.bind(this)); - // Fork the promise chain so we can log the error and let our caller see it too. - buPromise.then(null, e => logger.warn("Error in background update", e)); - return buPromise; - }, - - /** - * Adds a add-on to the list of detected changes for this startup. If - * addStartupChange is called multiple times for the same add-on in the same - * startup then only the most recent change will be remembered. - * - * @param aType - * The type of change as a string. Providers can define their own - * types of changes or use the existing defined STARTUP_CHANGE_* - * constants - * @param aID - * The ID of the add-on - */ - addStartupChange: function(aType, aID) { - if (!aType || typeof aType != "string") - throw Components.Exception("aType must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (!aID || typeof aID != "string") - throw Components.Exception("aID must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (gStartupComplete) - return; - logger.debug("Registering startup change '" + aType + "' for " + aID); - - // Ensure that an ID is only listed in one type of change - for (let type in this.startupChanges) - this.removeStartupChange(type, aID); - - if (!(aType in this.startupChanges)) - this.startupChanges[aType] = []; - this.startupChanges[aType].push(aID); - }, - - /** - * Removes a startup change for an add-on. - * - * @param aType - * The type of change - * @param aID - * The ID of the add-on - */ - removeStartupChange: function(aType, aID) { - if (!aType || typeof aType != "string") - throw Components.Exception("aType must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (!aID || typeof aID != "string") - throw Components.Exception("aID must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (gStartupComplete) - return; - - if (!(aType in this.startupChanges)) - return; - - this.startupChanges[aType] = this.startupChanges[aType].filter(aItem => aItem != aID); - }, - - /** - * Calls all registered AddonManagerListeners with an event. Any parameters - * after the method parameter are passed to the listener. - * - * @param aMethod - * The method on the listeners to call - */ - callManagerListeners: function(aMethod, ...aArgs) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMethod || typeof aMethod != "string") - throw Components.Exception("aMethod must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - let managerListeners = this.managerListeners.slice(0); - for (let listener of managerListeners) { - try { - if (aMethod in listener) - listener[aMethod].apply(listener, aArgs); - } - catch (e) { - logger.warn("AddonManagerListener threw exception when calling " + aMethod, e); - } - } - }, - - /** - * Calls all registered InstallListeners with an event. Any parameters after - * the extraListeners parameter are passed to the listener. - * - * @param aMethod - * The method on the listeners to call - * @param aExtraListeners - * An optional array of extra InstallListeners to also call - * @return false if any of the listeners returned false, true otherwise - */ - callInstallListeners: function(aMethod, - aExtraListeners, ...aArgs) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMethod || typeof aMethod != "string") - throw Components.Exception("aMethod must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (aExtraListeners && !Array.isArray(aExtraListeners)) - throw Components.Exception("aExtraListeners must be an array or null", - Cr.NS_ERROR_INVALID_ARG); - - let result = true; - let listeners; - if (aExtraListeners) - listeners = aExtraListeners.concat(this.installListeners); - else - listeners = this.installListeners.slice(0); - - for (let listener of listeners) { - try { - if (aMethod in listener) { - if (listener[aMethod].apply(listener, aArgs) === false) - result = false; - } - } - catch (e) { - logger.warn("InstallListener threw exception when calling " + aMethod, e); - } - } - return result; - }, - - /** - * Calls all registered AddonListeners with an event. Any parameters after - * the method parameter are passed to the listener. - * - * @param aMethod - * The method on the listeners to call - */ - callAddonListeners: function(aMethod, ...aArgs) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMethod || typeof aMethod != "string") - throw Components.Exception("aMethod must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - let addonListeners = this.addonListeners.slice(0); - for (let listener of addonListeners) { - try { - if (aMethod in listener) - listener[aMethod].apply(listener, aArgs); - } - catch (e) { - logger.warn("AddonListener threw exception when calling " + aMethod, e); - } - } - }, - - /** - * Notifies all providers that an add-on has been enabled when that type of - * add-on only supports a single add-on being enabled at a time. This allows - * the providers to disable theirs if necessary. - * - * @param aID - * The ID of the enabled add-on - * @param aType - * The type of the enabled add-on - * @param aPendingRestart - * A boolean indicating if the change will only take place the next - * time the application is restarted - */ - notifyAddonChanged: function(aID, aType, aPendingRestart) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (aID && typeof aID != "string") - throw Components.Exception("aID must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - if (!aType || typeof aType != "string") - throw Components.Exception("aType must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - // Temporary hack until bug 520124 lands. - // We can get here during synchronous startup, at which point it's - // considered unsafe (and therefore disallowed by AddonManager.jsm) to - // access providers that haven't been initialized yet. Since this is when - // XPIProvider is starting up, XPIProvider can't access itself via APIs - // going through AddonManager.jsm. Furthermore, LightweightThemeManager may - // not be initialized until after XPIProvider is, and therefore would also - // be unaccessible during XPIProvider startup. Thankfully, these are the - // only two uses of this API, and we know it's safe to use this API with - // both providers; so we have this hack to allow bypassing the normal - // safetey guard. - // The notifyAddonChanged/addonChanged API will be unneeded and therefore - // removed by bug 520124, so this is a temporary quick'n'dirty hack. - let providers = [...this.providers, ...this.pendingProviders]; - for (let provider of providers) { - callProvider(provider, "addonChanged", null, aID, aType, aPendingRestart); - } - }, - - /** - * Notifies all providers they need to update the appDisabled property for - * their add-ons in response to an application change such as a blocklist - * update. - */ - updateAddonAppDisabledStates: function() { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - this.callProviders("updateAddonAppDisabledStates"); - }, - - /** - * Notifies all providers that the repository has updated its data for - * installed add-ons. - * - * @param aCallback - * Function to call when operation is complete. - */ - updateAddonRepositoryData: function(aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", { - nextObject: function(aCaller, aProvider) { - callProviderAsync(aProvider, "updateAddonRepositoryData", - aCaller.callNext.bind(aCaller)); - }, - noMoreObjects: function(aCaller) { - safeCall(aCallback); - // only tests should care about this - Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null); - } - }); - }, - - /** - * Asynchronously gets an AddonInstall for a URL. - * - * @param aUrl - * The string represenation of the URL the add-on is located at - * @param aCallback - * A callback to pass the AddonInstall to - * @param aMimetype - * The mimetype of the add-on - * @param aHash - * An optional hash of the add-on - * @param aName - * An optional placeholder name while the add-on is being downloaded - * @param aIcons - * Optional placeholder icons while the add-on is being downloaded - * @param aVersion - * An optional placeholder version while the add-on is being downloaded - * @param aLoadGroup - * An optional nsILoadGroup to associate any network requests with - * @throws if the aUrl, aCallback or aMimetype arguments are not specified - */ - getInstallForURL: function(aUrl, aCallback, aMimetype, - aHash, aName, aIcons, - aVersion, aBrowser) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aUrl || typeof aUrl != "string") - throw Components.Exception("aURL must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - if (!aMimetype || typeof aMimetype != "string") - throw Components.Exception("aMimetype must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (aHash && typeof aHash != "string") - throw Components.Exception("aHash must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - if (aName && typeof aName != "string") - throw Components.Exception("aName must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - if (aIcons) { - if (typeof aIcons == "string") - aIcons = { "32": aIcons }; - else if (typeof aIcons != "object") - throw Components.Exception("aIcons must be a string, an object or null", - Cr.NS_ERROR_INVALID_ARG); - } else { - aIcons = {}; - } - - if (aVersion && typeof aVersion != "string") - throw Components.Exception("aVersion must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - if (aBrowser && (!(aBrowser instanceof Ci.nsIDOMElement))) - throw Components.Exception("aBrowser must be a nsIDOMElement or null", - Cr.NS_ERROR_INVALID_ARG); - - let providers = [...this.providers]; - for (let provider of providers) { - if (callProvider(provider, "supportsMimetype", false, aMimetype)) { - callProviderAsync(provider, "getInstallForURL", - aUrl, aHash, aName, aIcons, aVersion, aBrowser, - function getInstallForURL_safeCall(aInstall) { - safeCall(aCallback, aInstall); - }); - return; - } - } - safeCall(aCallback, null); - }, - - /** - * Asynchronously gets an AddonInstall for an nsIFile. - * - * @param aFile - * The nsIFile where the add-on is located - * @param aCallback - * A callback to pass the AddonInstall to - * @param aMimetype - * An optional mimetype hint for the add-on - * @throws if the aFile or aCallback arguments are not specified - */ - getInstallForFile: function(aFile, aCallback, aMimetype) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!(aFile instanceof Ci.nsIFile)) - throw Components.Exception("aFile must be a nsIFile", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - if (aMimetype && typeof aMimetype != "string") - throw Components.Exception("aMimetype must be a string or null", - Cr.NS_ERROR_INVALID_ARG); - - new AsyncObjectCaller(this.providers, "getInstallForFile", { - nextObject: function(aCaller, aProvider) { - callProviderAsync(aProvider, "getInstallForFile", aFile, - function(aInstall) { - if (aInstall) - safeCall(aCallback, aInstall); - else - aCaller.callNext(); - }); - }, - - noMoreObjects: function(aCaller) { - safeCall(aCallback, null); - } - }); - }, - - /** - * Asynchronously gets all current AddonInstalls optionally limiting to a list - * of types. - * - * @param aTypes - * An optional array of types to retrieve. Each type is a string name - * @param aCallback - * A callback which will be passed an array of AddonInstalls - * @throws If the aCallback argument is not specified - */ - getInstallsByTypes: function(aTypes, aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (aTypes && !Array.isArray(aTypes)) - throw Components.Exception("aTypes must be an array or null", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - let installs = []; - - new AsyncObjectCaller(this.providers, "getInstallsByTypes", { - nextObject: function(aCaller, aProvider) { - callProviderAsync(aProvider, "getInstallsByTypes", aTypes, - function(aProviderInstalls) { - if (aProviderInstalls) { - installs = installs.concat(aProviderInstalls); - } - aCaller.callNext(); - }); - }, - - noMoreObjects: function(aCaller) { - safeCall(aCallback, installs); - } - }); - }, - - /** - * Asynchronously gets all current AddonInstalls. - * - * @param aCallback - * A callback which will be passed an array of AddonInstalls - */ - getAllInstalls: function(aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - this.getInstallsByTypes(null, aCallback); - }, - - /** - * Synchronously map a URI to the corresponding Addon ID. - * - * Mappable URIs are limited to in-application resources belonging to the - * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. - * but do not include URIs from meta data, such as the add-on homepage. - * - * @param aURI - * nsIURI to map to an addon id - * @return string containing the Addon ID or null - * @see amIAddonManager.mapURIToAddonID - */ - mapURIToAddonID: function(aURI) { - if (!(aURI instanceof Ci.nsIURI)) { - throw Components.Exception("aURI is not a nsIURI", - Cr.NS_ERROR_INVALID_ARG); - } - - // Try all providers - let providers = [...this.providers]; - for (let provider of providers) { - var id = callProvider(provider, "mapURIToAddonID", null, aURI); - if (id !== null) { - return id; - } - } - - return null; - }, - - /** - * Checks whether installation is enabled for a particular mimetype. - * - * @param aMimetype - * The mimetype to check - * @return true if installation is enabled for the mimetype - */ - isInstallEnabled: function(aMimetype) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMimetype || typeof aMimetype != "string") - throw Components.Exception("aMimetype must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - let providers = [...this.providers]; - for (let provider of providers) { - if (callProvider(provider, "supportsMimetype", false, aMimetype) && - callProvider(provider, "isInstallEnabled")) - return true; - } - return false; - }, - - /** - * Checks whether a particular source is allowed to install add-ons of a - * given mimetype. - * - * @param aMimetype - * The mimetype of the add-on - * @param aInstallingPrincipal - * The nsIPrincipal that initiated the install - * @return true if the source is allowed to install this mimetype - */ - isInstallAllowed: function(aMimetype, aInstallingPrincipal) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMimetype || typeof aMimetype != "string") - throw Components.Exception("aMimetype must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) - throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", - Cr.NS_ERROR_INVALID_ARG); - - let providers = [...this.providers]; - for (let provider of providers) { - if (callProvider(provider, "supportsMimetype", false, aMimetype) && - callProvider(provider, "isInstallAllowed", null, aInstallingPrincipal)) - return true; - } - return false; - }, - - /** - * Starts installation of an array of AddonInstalls notifying the registered - * web install listener of blocked or started installs. - * - * @param aMimetype - * The mimetype of add-ons being installed - * @param aBrowser - * The optional browser element that started the installs - * @param aInstallingPrincipal - * The nsIPrincipal that initiated the install - * @param aInstalls - * The array of AddonInstalls to be installed - */ - installAddonsFromWebpage: function(aMimetype, aBrowser, - aInstallingPrincipal, aInstalls) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aMimetype || typeof aMimetype != "string") - throw Components.Exception("aMimetype must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (aBrowser && !(aBrowser instanceof Ci.nsIDOMElement)) - throw Components.Exception("aSource must be a nsIDOMElement, or null", - Cr.NS_ERROR_INVALID_ARG); - - if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) - throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", - Cr.NS_ERROR_INVALID_ARG); - - if (!Array.isArray(aInstalls)) - throw Components.Exception("aInstalls must be an array", - Cr.NS_ERROR_INVALID_ARG); - - if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) { - logger.warn("No web installer available, cancelling all installs"); - for (let install of aInstalls) - install.cancel(); - return; - } - - // When a chrome in-content UI has loaded a inside to host a - // website we want to do our security checks on the inner-browser but - // notify front-end that install events came from the outer-browser (the - // main tab's browser). Check this by seeing if the browser we've been - // passed is in a content type docshell and if so get the outer-browser. - let topBrowser = aBrowser; - let docShell = aBrowser.ownerDocument.defaultView - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIDocShellTreeItem); - if (docShell.itemType == Ci.nsIDocShellTreeItem.typeContent) - topBrowser = docShell.chromeEventHandler; - - try { - let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]. - getService(Ci.amIWebInstallListener); - - if (!this.isInstallEnabled(aMimetype)) { - for (let install of aInstalls) - install.cancel(); - - weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length); - return; - } - else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) { - for (let install of aInstalls) - install.cancel(); - - if (weblistener instanceof Ci.amIWebInstallListener2) { - weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length); - } - return; - } - - // The installs may start now depending on the web install listener, - // listen for the browser navigating to a new origin and cancel the - // installs in that case. - new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls); - - if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) { - if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length)) { - for (let install of aInstalls) - install.install(); - } - } - else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI, - aInstalls, aInstalls.length)) { - for (let install of aInstalls) - install.install(); - } - } - catch (e) { - // In the event that the weblistener throws during instantiation or when - // calling onWebInstallBlocked or onWebInstallRequested all of the - // installs should get cancelled. - logger.warn("Failure calling web installer", e); - for (let install of aInstalls) - install.cancel(); - } - }, - - /** - * Adds a new InstallListener if the listener is not already registered. - * - * @param aListener - * The InstallListener to add - */ - addInstallListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be a InstallListener object", - Cr.NS_ERROR_INVALID_ARG); - - if (!this.installListeners.some(function(i) { - return i == aListener; })) - this.installListeners.push(aListener); - }, - - /** - * Removes an InstallListener if the listener is registered. - * - * @param aListener - * The InstallListener to remove - */ - removeInstallListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be a InstallListener object", - Cr.NS_ERROR_INVALID_ARG); - - let pos = 0; - while (pos < this.installListeners.length) { - if (this.installListeners[pos] == aListener) - this.installListeners.splice(pos, 1); - else - pos++; - } - }, - /* - * Adds new or overrides existing UpgradeListener. - * - * @param aInstanceID - * The instance ID of an addon to register a listener for. - * @param aCallback - * The callback to invoke when updates are available for this addon. - * @throws if there is no addon matching the instanceID - */ - addUpgradeListener: function(aInstanceID, aCallback) { - if (!aInstanceID || typeof aInstanceID != "symbol") - throw Components.Exception("aInstanceID must be a symbol", - Cr.NS_ERROR_INVALID_ARG); - - if (!aCallback || typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - this.getAddonByInstanceID(aInstanceID).then(wrapper => { - if (!wrapper) { - throw Error("No addon matching instanceID:", aInstanceID.toString()); - } - let addonId = wrapper.addonId(); - logger.debug(`Registering upgrade listener for ${addonId}`); - this.upgradeListeners.set(addonId, aCallback); - }); - }, - - /** - * Removes an UpgradeListener if the listener is registered. - * - * @param aInstanceID - * The instance ID of the addon to remove - */ - removeUpgradeListener: function(aInstanceID) { - if (!aInstanceID || typeof aInstanceID != "symbol") - throw Components.Exception("aInstanceID must be a symbol", - Cr.NS_ERROR_INVALID_ARG); - - this.getAddonByInstanceID(aInstanceID).then(addon => { - if (!addon) { - throw Error("No addon for instanceID:", aInstanceID.toString()); - } - if (this.upgradeListeners.has(addon.id)) { - this.upgradeListeners.delete(addon.id); - } else { - throw Error("No upgrade listener registered for addon ID:", addon.id); - } - }); - }, - - /** - * Installs a temporary add-on from a local file or directory. - * @param aFile - * An nsIFile for the file or directory of the add-on to be - * temporarily installed. - * @return a Promise that rejects if the add-on is not a valid restartless - * add-on or if the same ID is already temporarily installed. - */ - installTemporaryAddon: function(aFile) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!(aFile instanceof Ci.nsIFile)) - throw Components.Exception("aFile must be a nsIFile", - Cr.NS_ERROR_INVALID_ARG); - - return AddonManagerInternal._getProviderByName("XPIProvider") - .installTemporaryAddon(aFile); - }, - - installAddonFromSources: function(aFile) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!(aFile instanceof Ci.nsIFile)) - throw Components.Exception("aFile must be a nsIFile", - Cr.NS_ERROR_INVALID_ARG); - - return AddonManagerInternal._getProviderByName("XPIProvider") - .installAddonFromSources(aFile); - }, - - /** - * Returns an Addon corresponding to an instance ID. - * @param aInstanceID - * An Addon Instance ID symbol - * @return {Promise} - * @resolves The found Addon or null if no such add-on exists. - * @rejects Never - * @throws if the aInstanceID argument is not specified - * or the AddonManager is not initialized - */ - getAddonByInstanceID: function(aInstanceID) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aInstanceID || typeof aInstanceID != "symbol") - throw Components.Exception("aInstanceID must be a Symbol()", - Cr.NS_ERROR_INVALID_ARG); - - return AddonManagerInternal._getProviderByName("XPIProvider") - .getAddonByInstanceID(aInstanceID); - }, - - /** - * Gets an icon from the icon set provided by the add-on - * that is closest to the specified size. - * - * The optional window parameter will be used to determine - * the screen resolution and select a more appropriate icon. - * Calling this method with 48px on retina screens will try to - * match an icon of size 96px. - * - * @param aAddon - * An addon object, meaning: - * An object with either an icons property that is a key-value - * list of icon size and icon URL, or an object having an iconURL - * and icon64URL property. - * @param aSize - * Ideal icon size in pixels - * @param aWindow - * Optional window object for determining the correct scale. - * @return {String} The absolute URL of the icon or null if the addon doesn't have icons - */ - getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) { - if (aWindow && aWindow.devicePixelRatio) { - aSize *= aWindow.devicePixelRatio; - } - - let icons = aAddon.icons; - - // certain addon-types only have iconURLs - if (!icons) { - icons = {}; - if (aAddon.iconURL) { - icons[32] = aAddon.iconURL; - icons[48] = aAddon.iconURL; - } - if (aAddon.icon64URL) { - icons[64] = aAddon.icon64URL; - } - } - - // quick return if the exact size was found - if (icons[aSize]) { - return icons[aSize]; - } - - let bestSize = null; - - for (let size of Object.keys(icons)) { - if (!INTEGER.test(size)) { - throw Components.Exception("Invalid icon size, must be an integer", - Cr.NS_ERROR_ILLEGAL_VALUE); - } - - size = parseInt(size, 10); - - if (!bestSize) { - bestSize = size; - continue; - } - - if (size > aSize && bestSize > aSize) { - // If both best size and current size are larger than the wanted size then choose - // the one closest to the wanted size - bestSize = Math.min(bestSize, size); - } - else { - // Otherwise choose the largest of the two so we'll prefer sizes as close to below aSize - // or above aSize - bestSize = Math.max(bestSize, size); - } - } - - return icons[bestSize] || null; - }, - - /** - * Asynchronously gets an add-on with a specific ID. - * - * @param aID - * The ID of the add-on to retrieve - * @return {Promise} - * @resolves The found Addon or null if no such add-on exists. - * @rejects Never - * @throws if the aID argument is not specified - */ - getAddonByID: function(aID) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aID || typeof aID != "string") - throw Components.Exception("aID must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - let promises = Array.from(this.providers, - p => promiseCallProvider(p, "getAddonByID", aID)); - return Promise.all(promises).then(aAddons => { - return aAddons.find(a => !!a) || null; - }); - }, - - /** - * Asynchronously get an add-on with a specific Sync GUID. - * - * @param aGUID - * String GUID of add-on to retrieve - * @param aCallback - * The callback to pass the retrieved add-on to. - * @throws if the aGUID or aCallback arguments are not specified - */ - getAddonBySyncGUID: function(aGUID, aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!aGUID || typeof aGUID != "string") - throw Components.Exception("aGUID must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", { - nextObject: function(aCaller, aProvider) { - callProviderAsync(aProvider, "getAddonBySyncGUID", aGUID, - function(aAddon) { - if (aAddon) { - safeCall(aCallback, aAddon); - } else { - aCaller.callNext(); - } - }); - }, - - noMoreObjects: function(aCaller) { - safeCall(aCallback, null); - } - }); - }, - - /** - * Asynchronously gets an array of add-ons. - * - * @param aIDs - * The array of IDs to retrieve - * @return {Promise} - * @resolves The array of found add-ons. - * @rejects Never - * @throws if the aIDs argument is not specified - */ - getAddonsByIDs: function(aIDs) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (!Array.isArray(aIDs)) - throw Components.Exception("aIDs must be an array", - Cr.NS_ERROR_INVALID_ARG); - - let promises = aIDs.map(a => AddonManagerInternal.getAddonByID(a)); - return Promise.all(promises); - }, - - /** - * Asynchronously gets add-ons of specific types. - * - * @param aTypes - * An optional array of types to retrieve. Each type is a string name - * @param aCallback - * The callback to pass an array of Addons to. - * @throws if the aCallback argument is not specified - */ - getAddonsByTypes: function(aTypes, aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (aTypes && !Array.isArray(aTypes)) - throw Components.Exception("aTypes must be an array or null", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - let addons = []; - - new AsyncObjectCaller(this.providers, "getAddonsByTypes", { - nextObject: function(aCaller, aProvider) { - callProviderAsync(aProvider, "getAddonsByTypes", aTypes, - function(aProviderAddons) { - if (aProviderAddons) { - addons = addons.concat(aProviderAddons); - } - aCaller.callNext(); - }); - }, - - noMoreObjects: function(aCaller) { - safeCall(aCallback, addons); - } - }); - }, - - /** - * Asynchronously gets all installed add-ons. - * - * @param aCallback - * A callback which will be passed an array of Addons - */ - getAllAddons: function(aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - this.getAddonsByTypes(null, aCallback); - }, - - /** - * Asynchronously gets add-ons that have operations waiting for an application - * restart to complete. - * - * @param aTypes - * An optional array of types to retrieve. Each type is a string name - * @param aCallback - * The callback to pass the array of Addons to - * @throws if the aCallback argument is not specified - */ - getAddonsWithOperationsByTypes: function(aTypes, aCallback) { - if (!gStarted) - throw Components.Exception("AddonManager is not initialized", - Cr.NS_ERROR_NOT_INITIALIZED); - - if (aTypes && !Array.isArray(aTypes)) - throw Components.Exception("aTypes must be an array or null", - Cr.NS_ERROR_INVALID_ARG); - - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - let addons = []; - - new AsyncObjectCaller(this.providers, "getAddonsWithOperationsByTypes", { - nextObject: function getAddonsWithOperationsByTypes_nextObject - (aCaller, aProvider) { - callProviderAsync(aProvider, "getAddonsWithOperationsByTypes", aTypes, - function getAddonsWithOperationsByTypes_concatAddons - (aProviderAddons) { - if (aProviderAddons) { - addons = addons.concat(aProviderAddons); - } - aCaller.callNext(); - }); - }, - - noMoreObjects: function(caller) { - safeCall(aCallback, addons); - } - }); - }, - - /** - * Adds a new AddonManagerListener if the listener is not already registered. - * - * @param aListener - * The listener to add - */ - addManagerListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be an AddonManagerListener object", - Cr.NS_ERROR_INVALID_ARG); - - if (!this.managerListeners.some(i => i == aListener)) - this.managerListeners.push(aListener); - }, - - /** - * Removes an AddonManagerListener if the listener is registered. - * - * @param aListener - * The listener to remove - */ - removeManagerListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be an AddonManagerListener object", - Cr.NS_ERROR_INVALID_ARG); - - let pos = 0; - while (pos < this.managerListeners.length) { - if (this.managerListeners[pos] == aListener) - this.managerListeners.splice(pos, 1); - else - pos++; - } - }, - - /** - * Adds a new AddonListener if the listener is not already registered. - * - * @param aListener - * The AddonListener to add - */ - addAddonListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be an AddonListener object", - Cr.NS_ERROR_INVALID_ARG); - - if (!this.addonListeners.some(i => i == aListener)) - this.addonListeners.push(aListener); - }, - - /** - * Removes an AddonListener if the listener is registered. - * - * @param aListener - * The AddonListener to remove - */ - removeAddonListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be an AddonListener object", - Cr.NS_ERROR_INVALID_ARG); - - let pos = 0; - while (pos < this.addonListeners.length) { - if (this.addonListeners[pos] == aListener) - this.addonListeners.splice(pos, 1); - else - pos++; - } - }, - - /** - * Adds a new TypeListener if the listener is not already registered. - * - * @param aListener - * The TypeListener to add - */ - addTypeListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be a TypeListener object", - Cr.NS_ERROR_INVALID_ARG); - - if (!this.typeListeners.some(i => i == aListener)) - this.typeListeners.push(aListener); - }, - - /** - * Removes an TypeListener if the listener is registered. - * - * @param aListener - * The TypeListener to remove - */ - removeTypeListener: function(aListener) { - if (!aListener || typeof aListener != "object") - throw Components.Exception("aListener must be a TypeListener object", - Cr.NS_ERROR_INVALID_ARG); - - let pos = 0; - while (pos < this.typeListeners.length) { - if (this.typeListeners[pos] == aListener) - this.typeListeners.splice(pos, 1); - else - pos++; - } - }, - - get addonTypes() { - // A read-only wrapper around the types dictionary - return new Proxy(this.types, { - defineProperty(target, property, descriptor) { - // Not allowed to define properties - return false; - }, - - deleteProperty(target, property) { - // Not allowed to delete properties - return false; - }, - - get(target, property, receiver) { - if (!target.hasOwnProperty(property)) - return undefined; - - return target[property].type; - }, - - getOwnPropertyDescriptor(target, property) { - if (!target.hasOwnProperty(property)) - return undefined; - - return { - value: target[property].type, - writable: false, - // Claim configurability to maintain the proxy invariants. - configurable: true, - enumerable: true - } - }, - - preventExtensions(target) { - // Not allowed to prevent adding new properties - return false; - }, - - set(target, property, value, receiver) { - // Not allowed to set properties - return false; - }, - - setPrototypeOf(target, prototype) { - // Not allowed to change prototype - return false; - } - }); - }, - - get autoUpdateDefault() { - return gAutoUpdateDefault; - }, - - set autoUpdateDefault(aValue) { - aValue = !!aValue; - if (aValue != gAutoUpdateDefault) - Services.prefs.setBoolPref(PREF_EM_AUTOUPDATE_DEFAULT, aValue); - return aValue; - }, - - get checkCompatibility() { - return gCheckCompatibility; - }, - - set checkCompatibility(aValue) { - aValue = !!aValue; - if (aValue != gCheckCompatibility) { - if (!aValue) - Services.prefs.setBoolPref(PREF_EM_CHECK_COMPATIBILITY, false); - else - Services.prefs.clearUserPref(PREF_EM_CHECK_COMPATIBILITY); - } - return aValue; - }, - - get strictCompatibility() { - return gStrictCompatibility; - }, - - set strictCompatibility(aValue) { - aValue = !!aValue; - if (aValue != gStrictCompatibility) - Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, aValue); - return aValue; - }, - - get checkUpdateSecurityDefault() { - return gCheckUpdateSecurityDefault; - }, - - get checkUpdateSecurity() { - return gCheckUpdateSecurity; - }, - - set checkUpdateSecurity(aValue) { - aValue = !!aValue; - if (aValue != gCheckUpdateSecurity) { - if (aValue != gCheckUpdateSecurityDefault) - Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, aValue); - else - Services.prefs.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY); - } - return aValue; - }, - - get updateEnabled() { - return gUpdateEnabled; - }, - - set updateEnabled(aValue) { - aValue = !!aValue; - if (aValue != gUpdateEnabled) - Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue); - return aValue; - }, - - get hotfixID() { - return gHotfixID; - }, - - webAPI: { - // installs maps integer ids to AddonInstall instances. - installs: new Map(), - nextInstall: 0, - - sendEvent: null, - setEventHandler(fn) { - this.sendEvent = fn; - }, - - getAddonByID(target, id) { - return new Promise(resolve => { - AddonManager.getAddonByID(id, (addon) => { - resolve(webAPIForAddon(addon)); - }); - }); - }, - - // helper to copy (and convert) the properties we care about - copyProps(install, obj) { - obj.state = AddonManager.stateToString(install.state); - obj.error = AddonManager.errorToString(install.error); - obj.progress = install.progress; - obj.maxProgress = install.maxProgress; - }, - - makeListener(id, mm) { - const events = [ - "onDownloadStarted", - "onDownloadProgress", - "onDownloadEnded", - "onDownloadCancelled", - "onDownloadFailed", - "onInstallStarted", - "onInstallEnded", - "onInstallCancelled", - "onInstallFailed", - ]; - - let listener = {}; - events.forEach(event => { - listener[event] = (install) => { - let data = {event, id}; - AddonManager.webAPI.copyProps(install, data); - this.sendEvent(mm, data); - } - }); - return listener; - }, - - forgetInstall(id) { - let info = this.installs.get(id); - if (!info) { - throw new Error(`forgetInstall cannot find ${id}`); - } - info.install.removeListener(info.listener); - this.installs.delete(id); - }, - - createInstall(target, options) { - // Throw an appropriate error if the given URL is not valid - // as an installation source. Return silently if it is okay. - function checkInstallUrl(url) { - let host = Services.io.newURI(options.url, null, null).host; - if (WEBAPI_INSTALL_HOSTS.includes(host)) { - return; - } - if (Services.prefs.getBoolPref(PREF_WEBAPI_TESTING) - && WEBAPI_TEST_INSTALL_HOSTS.includes(host)) { - return; - } - - throw new Error(`Install from ${host} not permitted`); - } - - return new Promise((resolve, reject) => { - try { - checkInstallUrl(options.url); - } catch (err) { - reject({message: err.message}); - return; - } - - let newInstall = install => { - let id = this.nextInstall++; - let listener = this.makeListener(id, target.messageManager); - install.addListener(listener); - - this.installs.set(id, {install, target, listener}); - - let result = {id}; - this.copyProps(install, result); - resolve(result); - }; - AddonManager.getInstallForURL(options.url, newInstall, "application/x-xpinstall", options.hash); - }); - }, - - addonUninstall(target, id) { - return new Promise(resolve => { - AddonManager.getAddonByID(id, addon => { - if (!addon) { - resolve(false); - } - - try { - addon.uninstall(); - resolve(true); - } catch (err) { - Cu.reportError(err); - resolve(false); - } - }); - }); - }, - - addonSetEnabled(target, id, value) { - return new Promise((resolve, reject) => { - AddonManager.getAddonByID(id, addon => { - if (!addon) { - reject({message: `No such addon ${id}`}); - } - addon.userDisabled = !value; - resolve(); - }); - }); - }, - - addonInstallDoInstall(target, id) { - let state = this.installs.get(id); - if (!state) { - return Promise.reject(`invalid id ${id}`); - } - return Promise.resolve(state.install.install()); - }, - - addonInstallCancel(target, id) { - let state = this.installs.get(id); - if (!state) { - return Promise.reject(`invalid id ${id}`); - } - return Promise.resolve(state.install.cancel()); - }, - - clearInstalls(ids) { - for (let id of ids) { - this.forgetInstall(id); - } - }, - - clearInstallsFrom(mm) { - for (let [id, info] of this.installs) { - if (info.target.messageManager == mm) { - this.forgetInstall(id); - } - } - }, - }, -}; - -/** - * Should not be used outside of core Mozilla code. This is a private API for - * the startup and platform integration code to use. Refer to the methods on - * AddonManagerInternal for documentation however note that these methods are - * subject to change at any time. - */ -this.AddonManagerPrivate = { - startup: function() { - AddonManagerInternal.startup(); - }, - - registerProvider: function(aProvider, aTypes) { - AddonManagerInternal.registerProvider(aProvider, aTypes); - }, - - unregisterProvider: function(aProvider) { - AddonManagerInternal.unregisterProvider(aProvider); - }, - - markProviderSafe: function(aProvider) { - AddonManagerInternal.markProviderSafe(aProvider); - }, - - backgroundUpdateCheck: function() { - return AddonManagerInternal.backgroundUpdateCheck(); - }, - - backgroundUpdateTimerHandler() { - // Don't call through to the real update check if no checks are enabled. - let checkHotfix = AddonManagerInternal.hotfixID && - Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && - Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); - - if (!AddonManagerInternal.updateEnabled && !checkHotfix) { - logger.info("Skipping background update check"); - return; - } - // Don't return the promise here, since the caller doesn't care. - AddonManagerInternal.backgroundUpdateCheck(); - }, - - addStartupChange: function(aType, aID) { - AddonManagerInternal.addStartupChange(aType, aID); - }, - - removeStartupChange: function(aType, aID) { - AddonManagerInternal.removeStartupChange(aType, aID); - }, - - notifyAddonChanged: function(aID, aType, aPendingRestart) { - AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart); - }, - - updateAddonAppDisabledStates: function() { - AddonManagerInternal.updateAddonAppDisabledStates(); - }, - - updateAddonRepositoryData: function(aCallback) { - AddonManagerInternal.updateAddonRepositoryData(aCallback); - }, - - callInstallListeners: function(...aArgs) { - return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal, - aArgs); - }, - - callAddonListeners: function(...aArgs) { - AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs); - }, - - AddonAuthor: AddonAuthor, - - AddonScreenshot: AddonScreenshot, - - AddonCompatibilityOverride: AddonCompatibilityOverride, - - AddonType: AddonType, - - recordTimestamp: function(name, value) { - AddonManagerInternal.recordTimestamp(name, value); - }, - - _simpleMeasures: {}, - recordSimpleMeasure: function(name, value) { - this._simpleMeasures[name] = value; - }, - - recordException: function(aModule, aContext, aException) { - let report = { - module: aModule, - context: aContext - }; - - if (typeof aException == "number") { - report.message = Components.Exception("", aException).name; - } - else { - report.message = aException.toString(); - if (aException.fileName) { - report.file = aException.fileName; - report.line = aException.lineNumber; - } - } - - this._simpleMeasures.exception = report; - }, - - getSimpleMeasures: function() { - return this._simpleMeasures; - }, - - getTelemetryDetails: function() { - return AddonManagerInternal.telemetryDetails; - }, - - setTelemetryDetails: function(aProvider, aDetails) { - AddonManagerInternal.telemetryDetails[aProvider] = aDetails; - }, - - // Start a timer, record a simple measure of the time interval when - // timer.done() is called - simpleTimer: function(aName) { - let startTime = Cu.now(); - return { - done: () => this.recordSimpleMeasure(aName, Math.round(Cu.now() - startTime)) - }; - }, - - /** - * Helper to call update listeners when no update is available. - * - * This can be used as an implementation for Addon.findUpdates() when - * no update mechanism is available. - */ - callNoUpdateListeners: function(addon, listener, reason, appVersion, platformVersion) { - if ("onNoCompatibilityUpdateAvailable" in listener) { - safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon); - } - if ("onNoUpdateAvailable" in listener) { - safeCall(listener.onNoUpdateAvailable.bind(listener), addon); - } - if ("onUpdateFinished" in listener) { - safeCall(listener.onUpdateFinished.bind(listener), addon); - } - }, - - get webExtensionsMinPlatformVersion() { - return gWebExtensionsMinPlatformVersion; - }, - - hasUpgradeListener: function(aId) { - return AddonManagerInternal.upgradeListeners.has(aId); - }, - - getUpgradeListener: function(aId) { - return AddonManagerInternal.upgradeListeners.get(aId); - }, -}; - -/** - * This is the public API that UI and developers should be calling. All methods - * just forward to AddonManagerInternal. - */ -this.AddonManager = { - // Constants for the AddonInstall.state property - // These will show up as AddonManager.STATE_* (eg, STATE_AVAILABLE) - _states: new Map([ - // The install is available for download. - ["STATE_AVAILABLE", 0], - // The install is being downloaded. - ["STATE_DOWNLOADING", 1], - // The install is checking for compatibility information. - ["STATE_CHECKING", 2], - // The install is downloaded and ready to install. - ["STATE_DOWNLOADED", 3], - // The download failed. - ["STATE_DOWNLOAD_FAILED", 4], - // The install has been postponed. - ["STATE_POSTPONED", 5], - // The add-on is being installed. - ["STATE_INSTALLING", 6], - // The add-on has been installed. - ["STATE_INSTALLED", 7], - // The install failed. - ["STATE_INSTALL_FAILED", 8], - // The install has been cancelled. - ["STATE_CANCELLED", 9], - ]), - - // Constants representing different types of errors while downloading an - // add-on. - // These will show up as AddonManager.ERROR_* (eg, ERROR_NETWORK_FAILURE) - _errors: new Map([ - // The download failed due to network problems. - ["ERROR_NETWORK_FAILURE", -1], - // The downloaded file did not match the provided hash. - ["ERROR_INCORRECT_HASH", -2], - // The downloaded file seems to be corrupted in some way. - ["ERROR_CORRUPT_FILE", -3], - // An error occured trying to write to the filesystem. - ["ERROR_FILE_ACCESS", -4], - // The add-on must be signed and isn't. - ["ERROR_SIGNEDSTATE_REQUIRED", -5], - // The downloaded add-on had a different type than expected. - ["ERROR_UNEXPECTED_ADDON_TYPE", -6], - // The addon did not have the expected ID - ["ERROR_INCORRECT_ID", -7], - ]), - - // These must be kept in sync with AddonUpdateChecker. - // No error was encountered. - UPDATE_STATUS_NO_ERROR: 0, - // The update check timed out - UPDATE_STATUS_TIMEOUT: -1, - // There was an error while downloading the update information. - UPDATE_STATUS_DOWNLOAD_ERROR: -2, - // The update information was malformed in some way. - UPDATE_STATUS_PARSE_ERROR: -3, - // The update information was not in any known format. - UPDATE_STATUS_UNKNOWN_FORMAT: -4, - // The update information was not correctly signed or there was an SSL error. - UPDATE_STATUS_SECURITY_ERROR: -5, - // The update was cancelled. - UPDATE_STATUS_CANCELLED: -6, - - // Constants to indicate why an update check is being performed - // Update check has been requested by the user. - UPDATE_WHEN_USER_REQUESTED: 1, - // Update check is necessary to see if the Addon is compatibile with a new - // version of the application. - UPDATE_WHEN_NEW_APP_DETECTED: 2, - // Update check is necessary because a new application has been installed. - UPDATE_WHEN_NEW_APP_INSTALLED: 3, - // Update check is a regular background update check. - UPDATE_WHEN_PERIODIC_UPDATE: 16, - // Update check is needed to check an Addon that is being installed. - UPDATE_WHEN_ADDON_INSTALLED: 17, - - // Constants for operations in Addon.pendingOperations - // Indicates that the Addon has no pending operations. - PENDING_NONE: 0, - // Indicates that the Addon will be enabled after the application restarts. - PENDING_ENABLE: 1, - // Indicates that the Addon will be disabled after the application restarts. - PENDING_DISABLE: 2, - // Indicates that the Addon will be uninstalled after the application restarts. - PENDING_UNINSTALL: 4, - // Indicates that the Addon will be installed after the application restarts. - PENDING_INSTALL: 8, - PENDING_UPGRADE: 16, - - // Constants for operations in Addon.operationsRequiringRestart - // Indicates that restart isn't required for any operation. - OP_NEEDS_RESTART_NONE: 0, - // Indicates that restart is required for enabling the addon. - OP_NEEDS_RESTART_ENABLE: 1, - // Indicates that restart is required for disabling the addon. - OP_NEEDS_RESTART_DISABLE: 2, - // Indicates that restart is required for uninstalling the addon. - OP_NEEDS_RESTART_UNINSTALL: 4, - // Indicates that restart is required for installing the addon. - OP_NEEDS_RESTART_INSTALL: 8, - - // Constants for permissions in Addon.permissions. - // Indicates that the Addon can be uninstalled. - PERM_CAN_UNINSTALL: 1, - // Indicates that the Addon can be enabled by the user. - PERM_CAN_ENABLE: 2, - // Indicates that the Addon can be disabled by the user. - PERM_CAN_DISABLE: 4, - // Indicates that the Addon can be upgraded. - PERM_CAN_UPGRADE: 8, - // Indicates that the Addon can be set to be optionally enabled - // on a case-by-case basis. - PERM_CAN_ASK_TO_ACTIVATE: 16, - - // General descriptions of where items are installed. - // Installed in this profile. - SCOPE_PROFILE: 1, - // Installed for all of this user's profiles. - SCOPE_USER: 2, - // Installed and owned by the application. - SCOPE_APPLICATION: 4, - // Installed for all users of the computer. - SCOPE_SYSTEM: 8, - // Installed temporarily - SCOPE_TEMPORARY: 16, - // The combination of all scopes. - SCOPE_ALL: 31, - - // Add-on type is expected to be displayed in the UI in a list. - VIEW_TYPE_LIST: "list", - - // Constants describing how add-on types behave. - - // If no add-ons of a type are installed, then the category for that add-on - // type should be hidden in the UI. - TYPE_UI_HIDE_EMPTY: 16, - // Indicates that this add-on type supports the ask-to-activate state. - // That is, add-ons of this type can be set to be optionally enabled - // on a case-by-case basis. - TYPE_SUPPORTS_ASK_TO_ACTIVATE: 32, - // The add-on type natively supports undo for restartless uninstalls. - // If this flag is not specified, the UI is expected to handle this via - // disabling the add-on, and performing the actual uninstall at a later time. - TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL: 64, - - // Constants for Addon.applyBackgroundUpdates. - // Indicates that the Addon should not update automatically. - AUTOUPDATE_DISABLE: 0, - // Indicates that the Addon should update automatically only if - // that's the global default. - AUTOUPDATE_DEFAULT: 1, - // Indicates that the Addon should update automatically. - AUTOUPDATE_ENABLE: 2, - - // Constants for how Addon options should be shown. - // Options will be opened in a new window - OPTIONS_TYPE_DIALOG: 1, - // Options will be displayed within the AM detail view - OPTIONS_TYPE_INLINE: 2, - // Options will be displayed in a new tab, if possible - OPTIONS_TYPE_TAB: 3, - // Same as OPTIONS_TYPE_INLINE, but no Preferences button will be shown. - // Used to indicate that only non-interactive information will be shown. - OPTIONS_TYPE_INLINE_INFO: 4, - // Similar to OPTIONS_TYPE_INLINE, but rather than generating inline - // options from a specially-formatted XUL file, the contents of the - // file are simply displayed in an inline element. - OPTIONS_TYPE_INLINE_BROWSER: 5, - - // Constants for displayed or hidden options notifications - // Options notification will be displayed - OPTIONS_NOTIFICATION_DISPLAYED: "addon-options-displayed", - // Options notification will be hidden - OPTIONS_NOTIFICATION_HIDDEN: "addon-options-hidden", - - // Constants for getStartupChanges, addStartupChange and removeStartupChange - // Add-ons that were detected as installed during startup. Doesn't include - // add-ons that were pending installation the last time the application ran. - STARTUP_CHANGE_INSTALLED: "installed", - // Add-ons that were detected as changed during startup. This includes an - // add-on moving to a different location, changing version or just having - // been detected as possibly changed. - STARTUP_CHANGE_CHANGED: "changed", - // Add-ons that were detected as uninstalled during startup. Doesn't include - // add-ons that were pending uninstallation the last time the application ran. - STARTUP_CHANGE_UNINSTALLED: "uninstalled", - // Add-ons that were detected as disabled during startup, normally because of - // an application change making an add-on incompatible. Doesn't include - // add-ons that were pending being disabled the last time the application ran. - STARTUP_CHANGE_DISABLED: "disabled", - // Add-ons that were detected as enabled during startup, normally because of - // an application change making an add-on compatible. Doesn't include - // add-ons that were pending being enabled the last time the application ran. - STARTUP_CHANGE_ENABLED: "enabled", - - // Constants for Addon.signedState. Any states that should cause an add-on - // to be unusable in builds that require signing should have negative values. - // Add-on signing is not required, e.g. because the pref is disabled. - SIGNEDSTATE_NOT_REQUIRED: undefined, - // Add-on is signed but signature verification has failed. - SIGNEDSTATE_BROKEN: -2, - // Add-on may be signed but by an certificate that doesn't chain to our - // our trusted certificate. - SIGNEDSTATE_UNKNOWN: -1, - // Add-on is unsigned. - SIGNEDSTATE_MISSING: 0, - // Add-on is preliminarily reviewed. - SIGNEDSTATE_PRELIMINARY: 1, - // Add-on is fully reviewed. - SIGNEDSTATE_SIGNED: 2, - // Add-on is system add-on. - SIGNEDSTATE_SYSTEM: 3, - - // Constants for the Addon.userDisabled property - // Indicates that the userDisabled state of this add-on is currently - // ask-to-activate. That is, it can be conditionally enabled on a - // case-by-case basis. - STATE_ASK_TO_ACTIVATE: "askToActivate", - - get __AddonManagerInternal__() { - return AppConstants.DEBUG ? AddonManagerInternal : undefined; - }, - - get isReady() { - return gStartupComplete && !gShutdownInProgress; - }, - - init() { - this._stateToString = new Map(); - for (let [name, value] of this._states) { - this[name] = value; - this._stateToString.set(value, name); - } - this._errorToString = new Map(); - for (let [name, value] of this._errors) { - this[name] = value; - this._errorToString.set(value, name); - } - }, - - stateToString(state) { - return this._stateToString.get(state); - }, - - errorToString(err) { - return err ? this._errorToString.get(err) : null; - }, - - getInstallForURL: function(aUrl, aCallback, aMimetype, - aHash, aName, aIcons, - aVersion, aBrowser) { - AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash, - aName, aIcons, aVersion, aBrowser); - }, - - getInstallForFile: function(aFile, aCallback, aMimetype) { - AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype); - }, - - /** - * Gets an array of add-on IDs that changed during the most recent startup. - * - * @param aType - * The type of startup change to get - * @return An array of add-on IDs - */ - getStartupChanges: function(aType) { - if (!(aType in AddonManagerInternal.startupChanges)) - return []; - return AddonManagerInternal.startupChanges[aType].slice(0); - }, - - getAddonByID: function(aID, aCallback) { - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - AddonManagerInternal.getAddonByID(aID) - .then(makeSafe(aCallback)) - .catch(logger.error); - }, - - getAddonBySyncGUID: function(aGUID, aCallback) { - AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback); - }, - - getAddonsByIDs: function(aIDs, aCallback) { - if (typeof aCallback != "function") - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - - AddonManagerInternal.getAddonsByIDs(aIDs) - .then(makeSafe(aCallback)) - .catch(logger.error); - }, - - getAddonsWithOperationsByTypes: function(aTypes, aCallback) { - AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes, aCallback); - }, - - getAddonsByTypes: function(aTypes, aCallback) { - AddonManagerInternal.getAddonsByTypes(aTypes, aCallback); - }, - - getAllAddons: function(aCallback) { - AddonManagerInternal.getAllAddons(aCallback); - }, - - getInstallsByTypes: function(aTypes, aCallback) { - AddonManagerInternal.getInstallsByTypes(aTypes, aCallback); - }, - - getAllInstalls: function(aCallback) { - AddonManagerInternal.getAllInstalls(aCallback); - }, - - mapURIToAddonID: function(aURI) { - return AddonManagerInternal.mapURIToAddonID(aURI); - }, - - isInstallEnabled: function(aType) { - return AddonManagerInternal.isInstallEnabled(aType); - }, - - isInstallAllowed: function(aType, aInstallingPrincipal) { - return AddonManagerInternal.isInstallAllowed(aType, aInstallingPrincipal); - }, - - installAddonsFromWebpage: function(aType, aBrowser, aInstallingPrincipal, - aInstalls) { - AddonManagerInternal.installAddonsFromWebpage(aType, aBrowser, - aInstallingPrincipal, - aInstalls); - }, - - installTemporaryAddon: function(aDirectory) { - return AddonManagerInternal.installTemporaryAddon(aDirectory); - }, - - installAddonFromSources: function(aDirectory) { - return AddonManagerInternal.installAddonFromSources(aDirectory); - }, - - getAddonByInstanceID: function(aInstanceID) { - return AddonManagerInternal.getAddonByInstanceID(aInstanceID); - }, - - addManagerListener: function(aListener) { - AddonManagerInternal.addManagerListener(aListener); - }, - - removeManagerListener: function(aListener) { - AddonManagerInternal.removeManagerListener(aListener); - }, - - addInstallListener: function(aListener) { - AddonManagerInternal.addInstallListener(aListener); - }, - - removeInstallListener: function(aListener) { - AddonManagerInternal.removeInstallListener(aListener); - }, - - getUpgradeListener: function(aId) { - return AddonManagerInternal.upgradeListeners.get(aId); - }, - - addUpgradeListener: function(aInstanceID, aCallback) { - AddonManagerInternal.addUpgradeListener(aInstanceID, aCallback); - }, - - removeUpgradeListener: function(aInstanceID) { - AddonManagerInternal.removeUpgradeListener(aInstanceID); - }, - - addAddonListener: function(aListener) { - AddonManagerInternal.addAddonListener(aListener); - }, - - removeAddonListener: function(aListener) { - AddonManagerInternal.removeAddonListener(aListener); - }, - - addTypeListener: function(aListener) { - AddonManagerInternal.addTypeListener(aListener); - }, - - removeTypeListener: function(aListener) { - AddonManagerInternal.removeTypeListener(aListener); - }, - - get addonTypes() { - return AddonManagerInternal.addonTypes; - }, - - /** - * Determines whether an Addon should auto-update or not. - * - * @param aAddon - * The Addon representing the add-on - * @return true if the addon should auto-update, false otherwise. - */ - shouldAutoUpdate: function(aAddon) { - if (!aAddon || typeof aAddon != "object") - throw Components.Exception("aAddon must be specified", - Cr.NS_ERROR_INVALID_ARG); - - if (!("applyBackgroundUpdates" in aAddon)) - return false; - if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE) - return true; - if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE) - return false; - return this.autoUpdateDefault; - }, - - get checkCompatibility() { - return AddonManagerInternal.checkCompatibility; - }, - - set checkCompatibility(aValue) { - AddonManagerInternal.checkCompatibility = aValue; - }, - - get strictCompatibility() { - return AddonManagerInternal.strictCompatibility; - }, - - set strictCompatibility(aValue) { - AddonManagerInternal.strictCompatibility = aValue; - }, - - get checkUpdateSecurityDefault() { - return AddonManagerInternal.checkUpdateSecurityDefault; - }, - - get checkUpdateSecurity() { - return AddonManagerInternal.checkUpdateSecurity; - }, - - set checkUpdateSecurity(aValue) { - AddonManagerInternal.checkUpdateSecurity = aValue; - }, - - get updateEnabled() { - return AddonManagerInternal.updateEnabled; - }, - - set updateEnabled(aValue) { - AddonManagerInternal.updateEnabled = aValue; - }, - - get autoUpdateDefault() { - return AddonManagerInternal.autoUpdateDefault; - }, - - set autoUpdateDefault(aValue) { - AddonManagerInternal.autoUpdateDefault = aValue; - }, - - get hotfixID() { - return AddonManagerInternal.hotfixID; - }, - - escapeAddonURI: function(aAddon, aUri, aAppVersion) { - return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion); - }, - - getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) { - return AddonManagerInternal.getPreferredIconURL(aAddon, aSize, aWindow); - }, - - get webAPI() { - return AddonManagerInternal.webAPI; - }, - - get shutdown() { - return gShutdownBarrier.client; - }, -}; - -this.AddonManager.init(); - -// load the timestamps module into AddonManagerInternal -Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", AddonManagerInternal); -Object.freeze(AddonManagerInternal); -Object.freeze(AddonManagerPrivate); -Object.freeze(AddonManager); diff --git a/toolkit/mozapps/extensions/AddonManagerWebAPI.cpp b/toolkit/mozapps/extensions/AddonManagerWebAPI.cpp deleted file mode 100644 index 3f2a7a529..000000000 --- a/toolkit/mozapps/extensions/AddonManagerWebAPI.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AddonManagerWebAPI.h" - -#include "mozilla/dom/Navigator.h" -#include "mozilla/dom/NavigatorBinding.h" - -#include "mozilla/Preferences.h" -#include "nsGlobalWindow.h" - -#include "nsIDocShell.h" -#include "nsIScriptObjectPrincipal.h" - -namespace mozilla { -using namespace mozilla::dom; - -static bool -IsValidHost(const nsACString& host) { - // This is ugly, but Preferences.h doesn't have support - // for default prefs or locked prefs - nsCOMPtr prefService (do_GetService(NS_PREFSERVICE_CONTRACTID)); - nsCOMPtr prefs; - if (prefService) { - prefService->GetDefaultBranch(nullptr, getter_AddRefs(prefs)); - bool isEnabled; - if (NS_SUCCEEDED(prefs->GetBoolPref("xpinstall.enabled", &isEnabled)) && !isEnabled) { - bool isLocked; - prefs->PrefIsLocked("xpinstall.enabled", &isLocked); - if (isLocked) { - return false; - } - } - } - - if (host.Equals("addons.mozilla.org") || - host.Equals("discovery.addons.mozilla.org") || - host.Equals("testpilot.firefox.com")) { - return true; - } - - // When testing allow access to the developer sites. - if (Preferences::GetBool("extensions.webapi.testing", false)) { - if (host.LowerCaseEqualsLiteral("addons.allizom.org") || - host.LowerCaseEqualsLiteral("discovery.addons.allizom.org") || - host.LowerCaseEqualsLiteral("addons-dev.allizom.org") || - host.LowerCaseEqualsLiteral("discovery.addons-dev.allizom.org") || - host.LowerCaseEqualsLiteral("testpilot.stage.mozaws.net") || - host.LowerCaseEqualsLiteral("testpilot.dev.mozaws.net") || - host.LowerCaseEqualsLiteral("example.com")) { - return true; - } - } - - return false; -} - -// Checks if the given uri is secure and matches one of the hosts allowed to -// access the API. -bool -AddonManagerWebAPI::IsValidSite(nsIURI* uri) -{ - if (!uri) { - return false; - } - - bool isSecure; - nsresult rv = uri->SchemeIs("https", &isSecure); - if (NS_FAILED(rv) || !isSecure) { - return false; - } - - nsAutoCString host; - rv = uri->GetHost(host); - if (NS_FAILED(rv)) { - return false; - } - - return IsValidHost(host); -} - -bool -AddonManagerWebAPI::IsAPIEnabled(JSContext* cx, JSObject* obj) -{ - nsGlobalWindow* global = xpc::WindowGlobalOrNull(obj); - if (!global) { - return false; - } - - nsCOMPtr win = global->AsInner(); - if (!win) { - return false; - } - - // Check that the current window and all parent frames are allowed access to - // the API. - while (win) { - nsCOMPtr sop = do_QueryInterface(win); - if (!sop) { - return false; - } - - nsCOMPtr principal = sop->GetPrincipal(); - if (!principal) { - return false; - } - - // Reaching a window with a system principal means we have reached - // privileged UI of some kind so stop at this point and allow access. - if (principal->GetIsSystemPrincipal()) { - return true; - } - - nsCOMPtr docShell = win->GetDocShell(); - if (!docShell) { - // This window has been torn down so don't allow access to the API. - return false; - } - - if (!IsValidSite(win->GetDocumentURI())) { - return false; - } - - // Checks whether there is a parent frame of the same type. This won't cross - // mozbrowser or chrome boundaries. - nsCOMPtr parent; - nsresult rv = docShell->GetSameTypeParent(getter_AddRefs(parent)); - if (NS_FAILED(rv)) { - return false; - } - - if (!parent) { - // No parent means we've hit a mozbrowser or chrome boundary so allow - // access to the API. - return true; - } - - nsIDocument* doc = win->GetDoc(); - if (!doc) { - return false; - } - - doc = doc->GetParentDocument(); - if (!doc) { - // Getting here means something has been torn down so fail safe. - return false; - } - - - win = doc->GetInnerWindow(); - } - - // Found a document with no inner window, don't grant access to the API. - return false; -} - -namespace dom { - -bool -AddonManagerPermissions::IsHostPermitted(const GlobalObject& /*unused*/, const nsAString& host) -{ - return IsValidHost(NS_ConvertUTF16toUTF8(host)); -} - -} // namespace mozilla::dom - - -} // namespace mozilla diff --git a/toolkit/mozapps/extensions/AddonManagerWebAPI.h b/toolkit/mozapps/extensions/AddonManagerWebAPI.h deleted file mode 100644 index 6830bc91f..000000000 --- a/toolkit/mozapps/extensions/AddonManagerWebAPI.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef addonmanagerwebapi_h_ -#define addonmanagerwebapi_h_ - -#include "nsPIDOMWindow.h" - -namespace mozilla { - -class AddonManagerWebAPI { -public: - static bool IsAPIEnabled(JSContext* cx, JSObject* obj); - -private: - static bool IsValidSite(nsIURI* uri); -}; - -namespace dom { - -class AddonManagerPermissions { -public: - static bool IsHostPermitted(const GlobalObject&, const nsAString& host); -}; - -} // namespace mozilla::dom - -} // namespace mozilla - -#endif // addonmanagerwebapi_h_ diff --git a/toolkit/mozapps/extensions/AddonPathService.cpp b/toolkit/mozapps/extensions/AddonPathService.cpp deleted file mode 100644 index 8a405c0ea..000000000 --- a/toolkit/mozapps/extensions/AddonPathService.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AddonPathService.h" - -#include "amIAddonManager.h" -#include "nsIURI.h" -#include "nsXULAppAPI.h" -#include "jsapi.h" -#include "nsServiceManagerUtils.h" -#include "nsLiteralString.h" -#include "nsThreadUtils.h" -#include "nsIIOService.h" -#include "nsNetUtil.h" -#include "nsIAddonPolicyService.h" -#include "nsIFileURL.h" -#include "nsIResProtocolHandler.h" -#include "nsIChromeRegistry.h" -#include "nsIJARURI.h" -#include "nsJSUtils.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/dom/ToJSValue.h" -#include "mozilla/AddonPathService.h" -#include "mozilla/Omnijar.h" - -#include - -namespace mozilla { - -struct PathEntryComparator -{ - typedef AddonPathService::PathEntry PathEntry; - - bool Equals(const PathEntry& entry1, const PathEntry& entry2) const - { - return entry1.mPath == entry2.mPath; - } - - bool LessThan(const PathEntry& entry1, const PathEntry& entry2) const - { - return entry1.mPath < entry2.mPath; - } -}; - -AddonPathService::AddonPathService() -{ -} - -AddonPathService::~AddonPathService() -{ - sInstance = nullptr; -} - -NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService) - -AddonPathService *AddonPathService::sInstance; - -/* static */ AddonPathService* -AddonPathService::GetInstance() -{ - if (!sInstance) { - sInstance = new AddonPathService(); - } - NS_ADDREF(sInstance); - return sInstance; -} - -static JSAddonId* -ConvertAddonId(const nsAString& addonIdString) -{ - AutoSafeJSContext cx; - JS::RootedValue strv(cx); - if (!mozilla::dom::ToJSValue(cx, addonIdString, &strv)) { - return nullptr; - } - JS::RootedString str(cx, strv.toString()); - return JS::NewAddonId(cx, str); -} - -JSAddonId* -AddonPathService::Find(const nsAString& path) -{ - // Use binary search to find the nearest entry that is <= |path|. - PathEntryComparator comparator; - unsigned index = mPaths.IndexOfFirstElementGt(PathEntry(path, nullptr), comparator); - if (index == 0) { - return nullptr; - } - const PathEntry& entry = mPaths[index - 1]; - - // Return the entry's addon if its path is a prefix of |path|. - if (StringBeginsWith(path, entry.mPath)) { - return entry.mAddonId; - } - return nullptr; -} - -NS_IMETHODIMP -AddonPathService::FindAddonId(const nsAString& path, nsAString& addonIdString) -{ - if (JSAddonId* id = Find(path)) { - JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id)); - AssignJSFlatString(addonIdString, flat); - } - return NS_OK; -} - -/* static */ JSAddonId* -AddonPathService::FindAddonId(const nsAString& path) -{ - // If no service has been created, then we're not going to find anything. - if (!sInstance) { - return nullptr; - } - - return sInstance->Find(path); -} - -NS_IMETHODIMP -AddonPathService::InsertPath(const nsAString& path, const nsAString& addonIdString) -{ - JSAddonId* addonId = ConvertAddonId(addonIdString); - - // Add the new path in sorted order. - PathEntryComparator comparator; - mPaths.InsertElementSorted(PathEntry(path, addonId), comparator); - return NS_OK; -} - -NS_IMETHODIMP -AddonPathService::MapURIToAddonId(nsIURI* aURI, nsAString& addonIdString) -{ - if (JSAddonId* id = MapURIToAddonID(aURI)) { - JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id)); - AssignJSFlatString(addonIdString, flat); - } - return NS_OK; -} - -static nsresult -ResolveURI(nsIURI* aURI, nsAString& out) -{ - bool equals; - nsresult rv; - nsCOMPtr uri; - nsAutoCString spec; - - // Resolve resource:// URIs. At the end of this if/else block, we - // have both spec and uri variables identifying the same URI. - if (NS_SUCCEEDED(aURI->SchemeIs("resource", &equals)) && equals) { - nsCOMPtr ioService = do_GetIOService(&rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - nsCOMPtr ph; - rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - nsCOMPtr irph(do_QueryInterface(ph, &rv)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - rv = irph->ResolveURI(aURI, spec); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - rv = ioService->NewURI(spec, nullptr, nullptr, getter_AddRefs(uri)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - } else if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &equals)) && equals) { - nsCOMPtr chromeReg = - mozilla::services::GetChromeRegistryService(); - if (NS_WARN_IF(!chromeReg)) - return NS_ERROR_UNEXPECTED; - - rv = chromeReg->ConvertChromeURL(aURI, getter_AddRefs(uri)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - } else { - uri = aURI; - } - - if (NS_SUCCEEDED(uri->SchemeIs("jar", &equals)) && equals) { - nsCOMPtr jarURI = do_QueryInterface(uri, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - nsCOMPtr jarFileURI; - rv = jarURI->GetJARFile(getter_AddRefs(jarFileURI)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - return ResolveURI(jarFileURI, out); - } - - if (NS_SUCCEEDED(uri->SchemeIs("file", &equals)) && equals) { - nsCOMPtr baseFileURL = do_QueryInterface(uri, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - nsCOMPtr file; - rv = baseFileURL->GetFile(getter_AddRefs(file)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - - return file->GetPath(out); - } - return NS_ERROR_FAILURE; -} - -JSAddonId* -MapURIToAddonID(nsIURI* aURI) -{ - if (!NS_IsMainThread() || !XRE_IsParentProcess()) { - return nullptr; - } - - bool equals; - nsresult rv; - if (NS_SUCCEEDED(aURI->SchemeIs("moz-extension", &equals)) && equals) { - nsCOMPtr service = do_GetService("@mozilla.org/addons/policy-service;1"); - if (service) { - nsString addonId; - rv = service->ExtensionURIToAddonId(aURI, addonId); - if (NS_FAILED(rv)) - return nullptr; - - return ConvertAddonId(addonId); - } - } - - nsAutoString filePath; - rv = ResolveURI(aURI, filePath); - if (NS_FAILED(rv)) - return nullptr; - - nsCOMPtr greJar = Omnijar::GetPath(Omnijar::GRE); - nsCOMPtr appJar = Omnijar::GetPath(Omnijar::APP); - if (greJar && appJar) { - nsAutoString greJarString, appJarString; - if (NS_FAILED(greJar->GetPath(greJarString)) || NS_FAILED(appJar->GetPath(appJarString))) - return nullptr; - - // If |aURI| is part of either Omnijar, then it can't be part of an - // add-on. This catches pretty much all URLs for Firefox content. - if (filePath.Equals(greJarString) || filePath.Equals(appJarString)) - return nullptr; - } - - // If it's not part of Firefox, we resort to binary searching through the - // add-on paths. - return AddonPathService::FindAddonId(filePath); -} - -} // namespace mozilla diff --git a/toolkit/mozapps/extensions/AddonPathService.h b/toolkit/mozapps/extensions/AddonPathService.h deleted file mode 100644 index f739b018f..000000000 --- a/toolkit/mozapps/extensions/AddonPathService.h +++ /dev/null @@ -1,55 +0,0 @@ -//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef AddonPathService_h -#define AddonPathService_h - -#include "amIAddonPathService.h" -#include "nsString.h" -#include "nsTArray.h" - -class nsIURI; -class JSAddonId; - -namespace mozilla { - -JSAddonId* -MapURIToAddonID(nsIURI* aURI); - -class AddonPathService final : public amIAddonPathService -{ -public: - AddonPathService(); - - static AddonPathService* GetInstance(); - - JSAddonId* Find(const nsAString& path); - static JSAddonId* FindAddonId(const nsAString& path); - - NS_DECL_ISUPPORTS - NS_DECL_AMIADDONPATHSERVICE - - struct PathEntry - { - nsString mPath; - JSAddonId* mAddonId; - - PathEntry(const nsAString& aPath, JSAddonId* aAddonId) - : mPath(aPath), mAddonId(aAddonId) - {} - }; - -private: - virtual ~AddonPathService(); - - // Paths are stored sorted in order of their mPath. - nsTArray mPaths; - - static AddonPathService* sInstance; -}; - -} // namespace mozilla - -#endif diff --git a/toolkit/mozapps/extensions/ChromeManifestParser.jsm b/toolkit/mozapps/extensions/ChromeManifestParser.jsm deleted file mode 100644 index 63f1db785..000000000 --- a/toolkit/mozapps/extensions/ChromeManifestParser.jsm +++ /dev/null @@ -1,157 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["ChromeManifestParser"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); - -const MSG_JAR_FLUSH = "AddonJarFlush"; - - -/** - * Sends local and remote notifications to flush a JAR file cache entry - * - * @param aJarFile - * The ZIP/XPI/JAR file as a nsIFile - */ -function flushJarCache(aJarFile) { - Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null); - Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster) - .broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path); -} - - -/** - * Parses chrome manifest files. - */ -this.ChromeManifestParser = { - - /** - * Reads and parses a chrome manifest file located at a specified URI, and all - * secondary manifests it references. - * - * @param aURI - * A nsIURI pointing to a chrome manifest. - * Typically a file: or jar: URI. - * @return Array of objects describing each manifest instruction, in the form: - * { type: instruction-type, baseURI: string-uri, args: [arguments] } - **/ - parseSync: function(aURI) { - function parseLine(aLine) { - let line = aLine.trim(); - if (line.length == 0 || line.charAt(0) == '#') - return; - let tokens = line.split(/\s+/); - let type = tokens.shift(); - if (type == "manifest") { - let uri = NetUtil.newURI(tokens.shift(), null, aURI); - data = data.concat(this.parseSync(uri)); - } else { - data.push({type: type, baseURI: baseURI, args: tokens}); - } - } - - let contents = ""; - try { - if (aURI.scheme == "jar") - contents = this._readFromJar(aURI); - else - contents = this._readFromFile(aURI); - } catch (e) { - // Silently fail. - } - - if (!contents) - return []; - - let baseURI = NetUtil.newURI(".", null, aURI).spec; - - let data = []; - let lines = contents.split("\n"); - lines.forEach(parseLine.bind(this)); - return data; - }, - - _readFromJar: function(aURI) { - let data = ""; - let entries = []; - let readers = []; - - try { - // Deconstrict URI, which can be nested jar: URIs. - let uri = aURI.clone(); - while (uri instanceof Ci.nsIJARURI) { - entries.push(uri.JAREntry); - uri = uri.JARFile; - } - - // Open the base jar. - let reader = Cc["@mozilla.org/libjar/zip-reader;1"]. - createInstance(Ci.nsIZipReader); - reader.open(uri.QueryInterface(Ci.nsIFileURL).file); - readers.push(reader); - - // Open the nested jars. - for (let i = entries.length - 1; i > 0; i--) { - let innerReader = Cc["@mozilla.org/libjar/zip-reader;1"]. - createInstance(Ci.nsIZipReader); - innerReader.openInner(reader, entries[i]); - readers.push(innerReader); - reader = innerReader; - } - - // First entry is the actual file we want to read. - let zis = reader.getInputStream(entries[0]); - data = NetUtil.readInputStreamToString(zis, zis.available()); - } - finally { - // Close readers in reverse order. - for (let i = readers.length - 1; i >= 0; i--) { - readers[i].close(); - flushJarCache(readers[i].file); - } - } - - return data; - }, - - _readFromFile: function(aURI) { - let file = aURI.QueryInterface(Ci.nsIFileURL).file; - if (!file.exists() || !file.isFile()) - return ""; - - let data = ""; - let fis = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - try { - fis.init(file, -1, -1, false); - data = NetUtil.readInputStreamToString(fis, fis.available()); - } finally { - fis.close(); - } - return data; - }, - - /** - * Detects if there were any instructions of a specified type in a given - * chrome manifest. - * - * @param aManifest - * Manifest data, as returned by ChromeManifestParser.parseSync(). - * @param aType - * Instruction type to filter by. - * @return True if any matching instructions were found in the manifest. - */ - hasType: function(aManifest, aType) { - return aManifest.some(entry => entry.type == aType); - } -}; diff --git a/toolkit/mozapps/extensions/DeferredSave.jsm b/toolkit/mozapps/extensions/DeferredSave.jsm deleted file mode 100644 index 89f82b265..000000000 --- a/toolkit/mozapps/extensions/DeferredSave.jsm +++ /dev/null @@ -1,275 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cu = Components.utils; -const Cc = Components.classes; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/osfile.jsm"); -/* globals OS*/ -Cu.import("resource://gre/modules/Promise.jsm"); - -// Make it possible to mock out timers for testing -var MakeTimer = () => Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - -this.EXPORTED_SYMBOLS = ["DeferredSave"]; - -// If delay parameter is not provided, default is 50 milliseconds. -const DEFAULT_SAVE_DELAY_MS = 50; - -Cu.import("resource://gre/modules/Log.jsm"); -// Configure a logger at the parent 'DeferredSave' level to format -// messages for all the modules under DeferredSave.* -const DEFERREDSAVE_PARENT_LOGGER_ID = "DeferredSave"; -var parentLogger = Log.repository.getLogger(DEFERREDSAVE_PARENT_LOGGER_ID); -parentLogger.level = Log.Level.Warn; -var formatter = new Log.BasicFormatter(); -// Set parent logger (and its children) to append to -// the Javascript section of the Browser Console -parentLogger.addAppender(new Log.ConsoleAppender(formatter)); -// Set parent logger (and its children) to -// also append to standard out -parentLogger.addAppender(new Log.DumpAppender(formatter)); - -// Provide the ability to enable/disable logging -// messages at runtime. -// If the "extensions.logging.enabled" preference is -// missing or 'false', messages at the WARNING and higher -// severity should be logged to the JS console and standard error. -// If "extensions.logging.enabled" is set to 'true', messages -// at DEBUG and higher should go to JS console and standard error. -Cu.import("resource://gre/modules/Services.jsm"); - -const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; -const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; - -/** -* Preference listener which listens for a change in the -* "extensions.logging.enabled" preference and changes the logging level of the -* parent 'addons' level logger accordingly. -*/ -var PrefObserver = { - init: function() { - Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); - Services.obs.addObserver(this, "xpcom-shutdown", false); - this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); - }, - - observe: function(aSubject, aTopic, aData) { - if (aTopic == "xpcom-shutdown") { - Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); - Services.obs.removeObserver(this, "xpcom-shutdown"); - } - else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { - let debugLogEnabled = false; - try { - debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); - } - catch (e) { - } - if (debugLogEnabled) { - parentLogger.level = Log.Level.Debug; - } - else { - parentLogger.level = Log.Level.Warn; - } - } - } -}; - -PrefObserver.init(); - -/** - * A module to manage deferred, asynchronous writing of data files - * to disk. Writing is deferred by waiting for a specified delay after - * a request to save the data, before beginning to write. If more than - * one save request is received during the delay, all requests are - * fulfilled by a single write. - * - * @constructor - * @param aPath - * String representing the full path of the file where the data - * is to be written. - * @param aDataProvider - * Callback function that takes no argument and returns the data to - * be written. If aDataProvider returns an ArrayBufferView, the - * bytes it contains are written to the file as is. - * If aDataProvider returns a String the data are UTF-8 encoded - * and then written to the file. - * @param [optional] aDelay - * The delay in milliseconds between the first saveChanges() call - * that marks the data as needing to be saved, and when the DeferredSave - * begins writing the data to disk. Default 50 milliseconds. - */ -this.DeferredSave = function(aPath, aDataProvider, aDelay) { - // Create a new logger (child of 'DeferredSave' logger) - // for use by this particular instance of DeferredSave object - let leafName = OS.Path.basename(aPath); - let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName; - this.logger = Log.repository.getLogger(logger_id); - - // @type {Deferred|null}, null when no data needs to be written - // @resolves with the result of OS.File.writeAtomic when all writes complete - // @rejects with the error from OS.File.writeAtomic if the write fails, - // or with the error from aDataProvider() if that throws. - this._pending = null; - - // @type {Promise}, completes when the in-progress write (if any) completes, - // kept as a resolved promise at other times to simplify logic. - // Because _deferredSave() always uses _writing.then() to execute - // its next action, we don't need a special case for whether a write - // is in progress - if the previous write is complete (and the _writing - // promise is already resolved/rejected), _writing.then() starts - // the next action immediately. - // - // @resolves with the result of OS.File.writeAtomic - // @rejects with the error from OS.File.writeAtomic - this._writing = Promise.resolve(0); - - // Are we currently waiting for a write to complete - this.writeInProgress = false; - - this._path = aPath; - this._dataProvider = aDataProvider; - - this._timer = null; - - // Some counters for telemetry - // The total number of times the file was written - this.totalSaves = 0; - - // The number of times the data became dirty while - // another save was in progress - this.overlappedSaves = 0; - - // Error returned by the most recent write (if any) - this._lastError = null; - - if (aDelay && (aDelay > 0)) - this._delay = aDelay; - else - this._delay = DEFAULT_SAVE_DELAY_MS; -} - -this.DeferredSave.prototype = { - get dirty() { - return this._pending || this.writeInProgress; - }, - - get lastError() { - return this._lastError; - }, - - // Start the pending timer if data is dirty - _startTimer: function() { - if (!this._pending) { - return; - } - - this.logger.debug("Starting timer"); - if (!this._timer) - this._timer = MakeTimer(); - this._timer.initWithCallback(() => this._deferredSave(), - this._delay, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - /** - * Mark the current stored data dirty, and schedule a flush to disk - * @return A Promise that will be resolved after the data is written to disk; - * the promise is resolved with the number of bytes written. - */ - saveChanges: function() { - this.logger.debug("Save changes"); - if (!this._pending) { - if (this.writeInProgress) { - this.logger.debug("Data changed while write in progress"); - this.overlappedSaves++; - } - this._pending = Promise.defer(); - // Wait until the most recent write completes or fails (if it hasn't already) - // and then restart our timer - this._writing.then(count => this._startTimer(), error => this._startTimer()); - } - return this._pending.promise; - }, - - _deferredSave: function() { - let pending = this._pending; - this._pending = null; - let writing = this._writing; - this._writing = pending.promise; - - // In either the success or the exception handling case, we don't need to handle - // the error from _writing here; it's already being handled in another then() - let toSave = null; - try { - toSave = this._dataProvider(); - } - catch (e) { - this.logger.error("Deferred save dataProvider failed", e); - writing.then(null, error => {}) - .then(count => { - pending.reject(e); - }); - return; - } - - writing.then(null, error => { return 0; }) - .then(count => { - this.logger.debug("Starting write"); - this.totalSaves++; - this.writeInProgress = true; - - OS.File.writeAtomic(this._path, toSave, {tmpPath: this._path + ".tmp"}) - .then( - result => { - this._lastError = null; - this.writeInProgress = false; - this.logger.debug("Write succeeded"); - pending.resolve(result); - }, - error => { - this._lastError = error; - this.writeInProgress = false; - this.logger.warn("Write failed", error); - pending.reject(error); - }); - }); - }, - - /** - * Immediately save the dirty data to disk, skipping - * the delay of normal operation. Note that the write - * still happens asynchronously in the worker - * thread from OS.File. - * - * There are four possible situations: - * 1) Nothing to flush - * 2) Data is not currently being written, in-memory copy is dirty - * 3) Data is currently being written, in-memory copy is clean - * 4) Data is being written and in-memory copy is dirty - * - * @return Promise that will resolve when all in-memory data - * has finished being flushed, returning the number of bytes - * written. If all in-memory data is clean, completes with the - * result of the most recent write. - */ - flush: function() { - // If we have pending changes, cancel our timer and set up the write - // immediately (_deferredSave queues the write for after the most - // recent write completes, if it hasn't already) - if (this._pending) { - this.logger.debug("Flush called while data is dirty"); - if (this._timer) { - this._timer.cancel(); - this._timer = null; - } - this._deferredSave(); - } - - return this._writing; - } -}; diff --git a/toolkit/mozapps/extensions/LightweightThemeManager.jsm b/toolkit/mozapps/extensions/LightweightThemeManager.jsm deleted file mode 100644 index 5dd41831d..000000000 --- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm +++ /dev/null @@ -1,909 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["LightweightThemeManager"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/AddonManager.jsm"); -/* globals AddonManagerPrivate*/ -Components.utils.import("resource://gre/modules/Services.jsm"); - -const ID_SUFFIX = "@personas.mozilla.org"; -const PREF_LWTHEME_TO_SELECT = "extensions.lwThemeToSelect"; -const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin"; -const PREF_EM_DSS_ENABLED = "extensions.dss.enabled"; -const ADDON_TYPE = "theme"; - -const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; - -const STRING_TYPE_NAME = "type.%ID%.name"; - -const DEFAULT_MAX_USED_THEMES_COUNT = 30; - -const MAX_PREVIEW_SECONDS = 30; - -const MANDATORY = ["id", "name", "headerURL"]; -const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL", - "previewURL", "author", "description", "homepageURL", - "updateURL", "version"]; - -const PERSIST_ENABLED = true; -const PERSIST_BYPASS_CACHE = false; -const PERSIST_FILES = { - headerURL: "lightweighttheme-header", - footerURL: "lightweighttheme-footer" -}; - -XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", - "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest", - "resource://gre/modules/ServiceRequest.jsm"); - - -XPCOMUtils.defineLazyGetter(this, "_prefs", () => { - return Services.prefs.getBranch("lightweightThemes."); -}); - -Object.defineProperty(this, "_maxUsedThemes", { - get: function() { - delete this._maxUsedThemes; - try { - this._maxUsedThemes = _prefs.getIntPref("maxUsedThemes"); - } - catch (e) { - this._maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; - } - return this._maxUsedThemes; - }, - - set: function(val) { - delete this._maxUsedThemes; - return this._maxUsedThemes = val; - }, - configurable: true, -}); - -// Holds the ID of the theme being enabled or disabled while sending out the -// events so cached AddonWrapper instances can return correct values for -// permissions and pendingOperations -var _themeIDBeingEnabled = null; -var _themeIDBeingDisabled = null; - -// Convert from the old storage format (in which the order of usedThemes -// was combined with isThemeSelected to determine which theme was selected) -// to the new one (where a selectedThemeID determines which theme is selected). -(function() { - let wasThemeSelected = false; - try { - wasThemeSelected = _prefs.getBoolPref("isThemeSelected"); - } catch (e) { } - - if (wasThemeSelected) { - _prefs.clearUserPref("isThemeSelected"); - let themes = []; - try { - themes = JSON.parse(_prefs.getComplexValue("usedThemes", - Ci.nsISupportsString).data); - } catch (e) { } - - if (Array.isArray(themes) && themes[0]) { - _prefs.setCharPref("selectedThemeID", themes[0].id); - } - } -})(); - -this.LightweightThemeManager = { - get name() { - return "LightweightThemeManager"; - }, - - // Themes that can be added for an application. They can't be removed, and - // will always show up at the top of the list. - _builtInThemes: new Map(), - - get usedThemes () { - let themes = []; - try { - themes = JSON.parse(_prefs.getComplexValue("usedThemes", - Ci.nsISupportsString).data); - } catch (e) { } - - themes.push(...this._builtInThemes.values()); - return themes; - }, - - get currentTheme () { - let selectedThemeID = null; - try { - selectedThemeID = _prefs.getCharPref("selectedThemeID"); - } catch (e) {} - - let data = null; - if (selectedThemeID) { - data = this.getUsedTheme(selectedThemeID); - } - return data; - }, - - get currentThemeForDisplay () { - var data = this.currentTheme; - - if (data && PERSIST_ENABLED) { - for (let key in PERSIST_FILES) { - try { - if (data[key] && _prefs.getBoolPref("persisted." + key)) - data[key] = _getLocalImageURI(PERSIST_FILES[key]).spec - + "?" + data.id + ";" + _version(data); - } catch (e) {} - } - } - - return data; - }, - - set currentTheme (aData) { - return _setCurrentTheme(aData, false); - }, - - setLocalTheme: function(aData) { - _setCurrentTheme(aData, true); - }, - - getUsedTheme: function(aId) { - var usedThemes = this.usedThemes; - for (let usedTheme of usedThemes) { - if (usedTheme.id == aId) - return usedTheme; - } - return null; - }, - - forgetUsedTheme: function(aId) { - let theme = this.getUsedTheme(aId); - if (!theme || LightweightThemeManager._builtInThemes.has(theme.id)) - return; - - let wrapper = new AddonWrapper(theme); - AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); - - var currentTheme = this.currentTheme; - if (currentTheme && currentTheme.id == aId) { - this.themeChanged(null); - AddonManagerPrivate.notifyAddonChanged(null, ADDON_TYPE, false); - } - - _updateUsedThemes(_usedThemesExceptId(aId)); - AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); - }, - - addBuiltInTheme: function(theme) { - if (!theme || !theme.id || this.usedThemes.some(t => t.id == theme.id)) { - throw new Error("Trying to add invalid builtIn theme"); - } - - this._builtInThemes.set(theme.id, theme); - - if (_prefs.getCharPref("selectedThemeID") == theme.id) { - this.currentTheme = theme; - } - }, - - forgetBuiltInTheme: function(id) { - if (!this._builtInThemes.has(id)) { - let currentTheme = this.currentTheme; - if (currentTheme && currentTheme.id == id) { - this.currentTheme = null; - } - } - return this._builtInThemes.delete(id); - }, - - clearBuiltInThemes: function() { - for (let id of this._builtInThemes.keys()) { - this.forgetBuiltInTheme(id); - } - }, - - previewTheme: function(aData) { - let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); - cancel.data = false; - Services.obs.notifyObservers(cancel, "lightweight-theme-preview-requested", - JSON.stringify(aData)); - if (cancel.data) - return; - - if (_previewTimer) - _previewTimer.cancel(); - else - _previewTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - _previewTimer.initWithCallback(_previewTimerCallback, - MAX_PREVIEW_SECONDS * 1000, - _previewTimer.TYPE_ONE_SHOT); - - _notifyWindows(aData); - }, - - resetPreview: function() { - if (_previewTimer) { - _previewTimer.cancel(); - _previewTimer = null; - _notifyWindows(this.currentThemeForDisplay); - } - }, - - parseTheme: function(aString, aBaseURI) { - try { - return _sanitizeTheme(JSON.parse(aString), aBaseURI, false); - } catch (e) { - return null; - } - }, - - updateCurrentTheme: function() { - try { - if (!_prefs.getBoolPref("update.enabled")) - return; - } catch (e) { - return; - } - - var theme = this.currentTheme; - if (!theme || !theme.updateURL) - return; - - var req = new ServiceRequest(); - - req.mozBackgroundRequest = true; - req.overrideMimeType("text/plain"); - req.open("GET", theme.updateURL, true); - // Prevent the request from reading from the cache. - req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; - // Prevent the request from writing to the cache. - req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; - - req.addEventListener("load", () => { - if (req.status != 200) - return; - - let newData = this.parseTheme(req.responseText, theme.updateURL); - if (!newData || - newData.id != theme.id || - _version(newData) == _version(theme)) - return; - - var currentTheme = this.currentTheme; - if (currentTheme && currentTheme.id == theme.id) - this.currentTheme = newData; - }, false); - - req.send(null); - }, - - /** - * Switches to a new lightweight theme. - * - * @param aData - * The lightweight theme to switch to - */ - themeChanged: function(aData) { - if (_previewTimer) { - _previewTimer.cancel(); - _previewTimer = null; - } - - if (aData) { - let usedThemes = _usedThemesExceptId(aData.id); - usedThemes.unshift(aData); - _updateUsedThemes(usedThemes); - if (PERSIST_ENABLED) { - LightweightThemeImageOptimizer.purge(); - _persistImages(aData, function() { - _notifyWindows(this.currentThemeForDisplay); - }.bind(this)); - } - } - - if (aData) - _prefs.setCharPref("selectedThemeID", aData.id); - else - _prefs.setCharPref("selectedThemeID", ""); - - _notifyWindows(aData); - Services.obs.notifyObservers(null, "lightweight-theme-changed", null); - }, - - /** - * Starts the Addons provider and enables the new lightweight theme if - * necessary. - */ - startup: function() { - if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) { - let id = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); - if (id) - this.themeChanged(this.getUsedTheme(id)); - else - this.themeChanged(null); - Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); - } - - _prefs.addObserver("", _prefObserver, false); - }, - - /** - * Shuts down the provider. - */ - shutdown: function() { - _prefs.removeObserver("", _prefObserver); - }, - - /** - * Called when a new add-on has been enabled when only one add-on of that type - * can be enabled. - * - * @param aId - * The ID of the newly enabled add-on - * @param aType - * The type of the newly enabled add-on - * @param aPendingRestart - * true if the newly enabled add-on will only become enabled after a - * restart - */ - addonChanged: function(aId, aType, aPendingRestart) { - if (aType != ADDON_TYPE) - return; - - let id = _getInternalID(aId); - let current = this.currentTheme; - - try { - let next = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); - if (id == next && aPendingRestart) - return; - - Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); - if (next) { - AddonManagerPrivate.callAddonListeners("onOperationCancelled", - new AddonWrapper(this.getUsedTheme(next))); - } - else if (id == current.id) { - AddonManagerPrivate.callAddonListeners("onOperationCancelled", - new AddonWrapper(current)); - return; - } - } - catch (e) { - } - - if (current) { - if (current.id == id) - return; - _themeIDBeingDisabled = current.id; - let wrapper = new AddonWrapper(current); - if (aPendingRestart) { - Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, ""); - AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, true); - } - else { - AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false); - this.themeChanged(null); - AddonManagerPrivate.callAddonListeners("onDisabled", wrapper); - } - _themeIDBeingDisabled = null; - } - - if (id) { - let theme = this.getUsedTheme(id); - _themeIDBeingEnabled = id; - let wrapper = new AddonWrapper(theme); - if (aPendingRestart) { - AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, true); - Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, id); - - // Flush the preferences to disk so they survive any crash - Services.prefs.savePrefFile(null); - } - else { - AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false); - this.themeChanged(theme); - AddonManagerPrivate.callAddonListeners("onEnabled", wrapper); - } - _themeIDBeingEnabled = null; - } - }, - - /** - * Called to get an Addon with a particular ID. - * - * @param aId - * The ID of the add-on to retrieve - * @param aCallback - * A callback to pass the Addon to - */ - getAddonByID: function(aId, aCallback) { - let id = _getInternalID(aId); - if (!id) { - aCallback(null); - return; - } - - let theme = this.getUsedTheme(id); - if (!theme) { - aCallback(null); - return; - } - - aCallback(new AddonWrapper(theme)); - }, - - /** - * Called to get Addons of a particular type. - * - * @param aTypes - * An array of types to fetch. Can be null to get all types. - * @param aCallback - * A callback to pass an array of Addons to - */ - getAddonsByTypes: function(aTypes, aCallback) { - if (aTypes && aTypes.indexOf(ADDON_TYPE) == -1) { - aCallback([]); - return; - } - - aCallback(this.usedThemes.map(a => new AddonWrapper(a))); - }, -}; - -const wrapperMap = new WeakMap(); -let themeFor = wrapper => wrapperMap.get(wrapper); - -/** - * The AddonWrapper wraps lightweight theme to provide the data visible to - * consumers of the AddonManager API. - */ -function AddonWrapper(aTheme) { - wrapperMap.set(this, aTheme); -} - -AddonWrapper.prototype = { - get id() { - return themeFor(this).id + ID_SUFFIX; - }, - - get type() { - return ADDON_TYPE; - }, - - get isActive() { - let current = LightweightThemeManager.currentTheme; - if (current) - return themeFor(this).id == current.id; - return false; - }, - - get name() { - return themeFor(this).name; - }, - - get version() { - let theme = themeFor(this); - return "version" in theme ? theme.version : ""; - }, - - get creator() { - let theme = themeFor(this); - return "author" in theme ? new AddonManagerPrivate.AddonAuthor(theme.author) : null; - }, - - get screenshots() { - let url = themeFor(this).previewURL; - return [new AddonManagerPrivate.AddonScreenshot(url)]; - }, - - get pendingOperations() { - let pending = AddonManager.PENDING_NONE; - if (this.isActive == this.userDisabled) - pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE; - return pending; - }, - - get operationsRequiringRestart() { - // If a non-default theme is in use then a restart will be required to - // enable lightweight themes unless dynamic theme switching is enabled - if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN)) { - try { - if (Services.prefs.getBoolPref(PREF_EM_DSS_ENABLED)) - return AddonManager.OP_NEEDS_RESTART_NONE; - } - catch (e) { - } - return AddonManager.OP_NEEDS_RESTART_ENABLE; - } - - return AddonManager.OP_NEEDS_RESTART_NONE; - }, - - get size() { - // The size changes depending on whether the theme is in use or not, this is - // probably not worth exposing. - return null; - }, - - get permissions() { - let permissions = 0; - - // Do not allow uninstall of builtIn themes. - if (!LightweightThemeManager._builtInThemes.has(themeFor(this).id)) - permissions = AddonManager.PERM_CAN_UNINSTALL; - if (this.userDisabled) - permissions |= AddonManager.PERM_CAN_ENABLE; - else - permissions |= AddonManager.PERM_CAN_DISABLE; - return permissions; - }, - - get userDisabled() { - let id = themeFor(this).id; - if (_themeIDBeingEnabled == id) - return false; - if (_themeIDBeingDisabled == id) - return true; - - try { - let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); - return id != toSelect; - } - catch (e) { - let current = LightweightThemeManager.currentTheme; - return !current || current.id != id; - } - }, - - set userDisabled(val) { - if (val == this.userDisabled) - return val; - - if (val) - LightweightThemeManager.currentTheme = null; - else - LightweightThemeManager.currentTheme = themeFor(this); - - return val; - }, - - // Lightweight themes are never disabled by the application - get appDisabled() { - return false; - }, - - // Lightweight themes are always compatible - get isCompatible() { - return true; - }, - - get isPlatformCompatible() { - return true; - }, - - get scope() { - return AddonManager.SCOPE_PROFILE; - }, - - get foreignInstall() { - return false; - }, - - uninstall: function() { - LightweightThemeManager.forgetUsedTheme(themeFor(this).id); - }, - - cancelUninstall: function() { - throw new Error("Theme is not marked to be uninstalled"); - }, - - findUpdates: function(listener, reason, appVersion, platformVersion) { - AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion); - }, - - // Lightweight themes are always compatible - isCompatibleWith: function(appVersion, platformVersion) { - return true; - }, - - // Lightweight themes are always securely updated - get providesUpdatesSecurely() { - return true; - }, - - // Lightweight themes are never blocklisted - get blocklistState() { - return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; - } -}; - -["description", "homepageURL", "iconURL"].forEach(function(prop) { - Object.defineProperty(AddonWrapper.prototype, prop, { - get: function() { - let theme = themeFor(this); - return prop in theme ? theme[prop] : null; - }, - enumarable: true, - }); -}); - -["installDate", "updateDate"].forEach(function(prop) { - Object.defineProperty(AddonWrapper.prototype, prop, { - get: function() { - let theme = themeFor(this); - return prop in theme ? new Date(theme[prop]) : null; - }, - enumarable: true, - }); -}); - -/** - * Converts the ID used by the public AddonManager API to an lightweight theme - * ID. - * - * @param id - * The ID to be converted - * - * @return the lightweight theme ID or null if the ID was not for a lightweight - * theme. - */ -function _getInternalID(id) { - if (!id) - return null; - let len = id.length - ID_SUFFIX.length; - if (len > 0 && id.substring(len) == ID_SUFFIX) - return id.substring(0, len); - return null; -} - -function _setCurrentTheme(aData, aLocal) { - aData = _sanitizeTheme(aData, null, aLocal); - - let needsRestart = (ADDON_TYPE == "theme") && - Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN); - - let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); - cancel.data = false; - Services.obs.notifyObservers(cancel, "lightweight-theme-change-requested", - JSON.stringify(aData)); - - if (aData) { - let theme = LightweightThemeManager.getUsedTheme(aData.id); - let isInstall = !theme || theme.version != aData.version; - if (isInstall) { - aData.updateDate = Date.now(); - if (theme && "installDate" in theme) - aData.installDate = theme.installDate; - else - aData.installDate = aData.updateDate; - - var oldWrapper = theme ? new AddonWrapper(theme) : null; - var wrapper = new AddonWrapper(aData); - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, - wrapper, oldWrapper, false); - AddonManagerPrivate.callAddonListeners("onInstalling", wrapper, false); - } - - let current = LightweightThemeManager.currentTheme; - let usedThemes = _usedThemesExceptId(aData.id); - if (current && current.id != aData.id) - usedThemes.splice(1, 0, aData); - else - usedThemes.unshift(aData); - _updateUsedThemes(usedThemes); - - if (isInstall) - AddonManagerPrivate.callAddonListeners("onInstalled", wrapper); - } - - if (cancel.data) - return null; - - AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null, - ADDON_TYPE, needsRestart); - - return LightweightThemeManager.currentTheme; -} - -function _sanitizeTheme(aData, aBaseURI, aLocal) { - if (!aData || typeof aData != "object") - return null; - - var resourceProtocols = ["http", "https", "resource"]; - if (aLocal) - resourceProtocols.push("file"); - var resourceProtocolExp = new RegExp("^(" + resourceProtocols.join("|") + "):"); - - function sanitizeProperty(prop) { - if (!(prop in aData)) - return null; - if (typeof aData[prop] != "string") - return null; - let val = aData[prop].trim(); - if (!val) - return null; - - if (!/URL$/.test(prop)) - return val; - - try { - val = _makeURI(val, aBaseURI ? _makeURI(aBaseURI) : null).spec; - if ((prop == "updateURL" ? /^https:/ : resourceProtocolExp).test(val)) - return val; - return null; - } - catch (e) { - return null; - } - } - - let result = {}; - for (let mandatoryProperty of MANDATORY) { - let val = sanitizeProperty(mandatoryProperty); - if (!val) - throw Components.results.NS_ERROR_INVALID_ARG; - result[mandatoryProperty] = val; - } - - for (let optionalProperty of OPTIONAL) { - let val = sanitizeProperty(optionalProperty); - if (!val) - continue; - result[optionalProperty] = val; - } - - return result; -} - -function _usedThemesExceptId(aId) { - return LightweightThemeManager.usedThemes.filter(function(t) { - return "id" in t && t.id != aId; - }); -} - -function _version(aThemeData) { - return aThemeData.version || ""; -} - -function _makeURI(aURL, aBaseURI) { - return Services.io.newURI(aURL, null, aBaseURI); -} - -function _updateUsedThemes(aList) { - // Remove app-specific themes before saving them to the usedThemes pref. - aList = aList.filter(theme => !LightweightThemeManager._builtInThemes.has(theme.id)); - - // Send uninstall events for all themes that need to be removed. - while (aList.length > _maxUsedThemes) { - let wrapper = new AddonWrapper(aList[aList.length - 1]); - AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); - aList.pop(); - AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); - } - - var str = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - str.data = JSON.stringify(aList); - _prefs.setComplexValue("usedThemes", Ci.nsISupportsString, str); - - Services.obs.notifyObservers(null, "lightweight-theme-list-changed", null); -} - -function _notifyWindows(aThemeData) { - Services.obs.notifyObservers(null, "lightweight-theme-styling-update", - JSON.stringify(aThemeData)); -} - -var _previewTimer; -var _previewTimerCallback = { - notify: function() { - LightweightThemeManager.resetPreview(); - } -}; - -/** - * Called when any of the lightweightThemes preferences are changed. - */ -function _prefObserver(aSubject, aTopic, aData) { - switch (aData) { - case "maxUsedThemes": - try { - _maxUsedThemes = _prefs.getIntPref(aData); - } - catch (e) { - _maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; - } - // Update the theme list to remove any themes over the number we keep - _updateUsedThemes(LightweightThemeManager.usedThemes); - break; - } -} - -function _persistImages(aData, aCallback) { - function onSuccess(key) { - return function () { - let current = LightweightThemeManager.currentTheme; - if (current && current.id == aData.id) { - _prefs.setBoolPref("persisted." + key, true); - } - if (--numFilesToPersist == 0 && aCallback) { - aCallback(); - } - }; - } - - let numFilesToPersist = 0; - for (let key in PERSIST_FILES) { - _prefs.setBoolPref("persisted." + key, false); - if (aData[key]) { - numFilesToPersist++; - _persistImage(aData[key], PERSIST_FILES[key], onSuccess(key)); - } - } -} - -function _getLocalImageURI(localFileName) { - var localFile = Services.dirsvc.get("ProfD", Ci.nsIFile); - localFile.append(localFileName); - return Services.io.newFileURI(localFile); -} - -function _persistImage(sourceURL, localFileName, successCallback) { - if (/^(file|resource):/.test(sourceURL)) - return; - - var targetURI = _getLocalImageURI(localFileName); - var sourceURI = _makeURI(sourceURL); - - var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] - .createInstance(Ci.nsIWebBrowserPersist); - - persist.persistFlags = - Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | - Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION | - (PERSIST_BYPASS_CACHE ? - Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE : - Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE); - - persist.progressListener = new _persistProgressListener(successCallback); - - persist.saveURI(sourceURI, null, - null, Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, - null, null, targetURI, null); -} - -function _persistProgressListener(successCallback) { - this.onLocationChange = function() {}; - this.onProgressChange = function() {}; - this.onStatusChange = function() {}; - this.onSecurityChange = function() {}; - this.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus) { - if (aRequest && - aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK && - aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) { - try { - if (aRequest.QueryInterface(Ci.nsIHttpChannel).requestSucceeded) { - // success - successCallback(); - return; - } - } catch (e) { } - // failure - } - }; -} - -AddonManagerPrivate.registerProvider(LightweightThemeManager, [ - new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS, - STRING_TYPE_NAME, - AddonManager.VIEW_TYPE_LIST, 5000) -]); diff --git a/toolkit/mozapps/extensions/addonManager.js b/toolkit/mozapps/extensions/addonManager.js deleted file mode 100644 index d34cbaf62..000000000 --- a/toolkit/mozapps/extensions/addonManager.js +++ /dev/null @@ -1,296 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This component serves as integration between the platform and AddonManager. - * It is responsible for initializing and shutting down the AddonManager as well - * as passing new installs from webpages to the AddonManager. - */ - -"use strict"; - -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -// The old XPInstall error codes -const EXECUTION_ERROR = -203; -const CANT_READ_ARCHIVE = -207; -const USER_CANCELLED = -210; -const DOWNLOAD_ERROR = -228; -const UNSUPPORTED_TYPE = -244; -const SUCCESS = 0; - -const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; -const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; - -const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest"; -const MSG_PROMISE_RESULT = "WebAPIPromiseResult"; -const MSG_INSTALL_EVENT = "WebAPIInstallEvent"; -const MSG_INSTALL_CLEANUP = "WebAPICleanup"; -const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest"; -const MSG_ADDON_EVENT = "WebAPIAddonEvent"; - -const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js"; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -var gSingleton = null; - -function amManager() { - Cu.import("resource://gre/modules/AddonManager.jsm"); - /* globals AddonManagerPrivate*/ - - Services.mm.loadFrameScript(CHILD_SCRIPT, true); - Services.mm.addMessageListener(MSG_INSTALL_ENABLED, this); - Services.mm.addMessageListener(MSG_INSTALL_ADDONS, this); - Services.mm.addMessageListener(MSG_PROMISE_REQUEST, this); - Services.mm.addMessageListener(MSG_INSTALL_CLEANUP, this); - Services.mm.addMessageListener(MSG_ADDON_EVENT_REQ, this); - - Services.obs.addObserver(this, "message-manager-close", false); - Services.obs.addObserver(this, "message-manager-disconnect", false); - - AddonManager.webAPI.setEventHandler(this.sendEvent); - - // Needed so receiveMessage can be called directly by JS callers - this.wrappedJSObject = this; -} - -amManager.prototype = { - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case "addons-startup": - AddonManagerPrivate.startup(); - break; - - case "message-manager-close": - case "message-manager-disconnect": - this.childClosed(aSubject); - break; - } - }, - - /** - * @see amIAddonManager.idl - */ - mapURIToAddonID: function(uri, id) { - id.value = AddonManager.mapURIToAddonID(uri); - return !!id.value; - }, - - /** - * @see amIWebInstaller.idl - */ - isInstallEnabled: function(aMimetype, aReferer) { - return AddonManager.isInstallEnabled(aMimetype); - }, - - /** - * @see amIWebInstaller.idl - */ - installAddonsFromWebpage: function(aMimetype, aBrowser, aInstallingPrincipal, - aUris, aHashes, aNames, aIcons, aCallback) { - if (aUris.length == 0) - return false; - - let retval = true; - if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) { - aCallback = null; - retval = false; - } - - let installs = []; - function buildNextInstall() { - if (aUris.length == 0) { - AddonManager.installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, installs); - return; - } - let uri = aUris.shift(); - AddonManager.getInstallForURL(uri, function(aInstall) { - function callCallback(aUri, aStatus) { - try { - aCallback.onInstallEnded(aUri, aStatus); - } - catch (e) { - Components.utils.reportError(e); - } - } - - if (aInstall) { - installs.push(aInstall); - if (aCallback) { - aInstall.addListener({ - onDownloadCancelled: function(aInstall) { - callCallback(uri, USER_CANCELLED); - }, - - onDownloadFailed: function(aInstall) { - if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) - callCallback(uri, CANT_READ_ARCHIVE); - else - callCallback(uri, DOWNLOAD_ERROR); - }, - - onInstallFailed: function(aInstall) { - callCallback(uri, EXECUTION_ERROR); - }, - - onInstallEnded: function(aInstall, aStatus) { - callCallback(uri, SUCCESS); - } - }); - } - } - else if (aCallback) { - aCallback.onInstallEnded(uri, UNSUPPORTED_TYPE); - } - buildNextInstall(); - }, aMimetype, aHashes.shift(), aNames.shift(), aIcons.shift(), null, aBrowser); - } - buildNextInstall(); - - return retval; - }, - - notify: function(aTimer) { - AddonManagerPrivate.backgroundUpdateTimerHandler(); - }, - - // Maps message manager instances for content processes to the associated - // AddonListener instances. - addonListeners: new Map(), - - _addAddonListener(target) { - if (!this.addonListeners.has(target)) { - let handler = (event, id, needsRestart) => { - target.sendAsyncMessage(MSG_ADDON_EVENT, {event, id, needsRestart}); - }; - let listener = { - onEnabling: (addon, needsRestart) => handler("onEnabling", addon.id, needsRestart), - onEnabled: (addon) => handler("onEnabled", addon.id, false), - onDisabling: (addon, needsRestart) => handler("onDisabling", addon.id, needsRestart), - onDisabled: (addon) => handler("onDisabled", addon.id, false), - onInstalling: (addon, needsRestart) => handler("onInstalling", addon.id, needsRestart), - onInstalled: (addon) => handler("onInstalled", addon.id, false), - onUninstalling: (addon, needsRestart) => handler("onUninstalling", addon.id, needsRestart), - onUninstalled: (addon) => handler("onUninstalled", addon.id, false), - onOperationCancelled: (addon) => handler("onOperationCancelled", addon.id, false), - }; - this.addonListeners.set(target, listener); - AddonManager.addAddonListener(listener); - } - }, - - _removeAddonListener(target) { - if (this.addonListeners.has(target)) { - AddonManager.removeAddonListener(this.addonListeners.get(target)); - this.addonListeners.delete(target); - } - }, - - /** - * messageManager callback function. - * - * Listens to requests from child processes for InstallTrigger - * activity, and sends back callbacks. - */ - receiveMessage: function(aMessage) { - let payload = aMessage.data; - - switch (aMessage.name) { - case MSG_INSTALL_ENABLED: - return AddonManager.isInstallEnabled(payload.mimetype); - - case MSG_INSTALL_ADDONS: { - let callback = null; - if (payload.callbackID != -1) { - let mm = aMessage.target.messageManager; - callback = { - onInstallEnded: function(url, status) { - mm.sendAsyncMessage(MSG_INSTALL_CALLBACK, { - callbackID: payload.callbackID, - url: url, - status: status - }); - }, - }; - } - - return this.installAddonsFromWebpage(payload.mimetype, - aMessage.target, payload.triggeringPrincipal, payload.uris, - payload.hashes, payload.names, payload.icons, callback); - } - - case MSG_PROMISE_REQUEST: { - let mm = aMessage.target.messageManager; - let resolve = (value) => { - mm.sendAsyncMessage(MSG_PROMISE_RESULT, { - callbackID: payload.callbackID, - resolve: value - }); - } - let reject = (value) => { - mm.sendAsyncMessage(MSG_PROMISE_RESULT, { - callbackID: payload.callbackID, - reject: value - }); - } - - let API = AddonManager.webAPI; - if (payload.type in API) { - API[payload.type](aMessage.target, ...payload.args).then(resolve, reject); - } - else { - reject("Unknown Add-on API request."); - } - break; - } - - case MSG_INSTALL_CLEANUP: { - AddonManager.webAPI.clearInstalls(payload.ids); - break; - } - - case MSG_ADDON_EVENT_REQ: { - let target = aMessage.target.messageManager; - if (payload.enabled) { - this._addAddonListener(target); - } else { - this._removeAddonListener(target); - } - } - } - return undefined; - }, - - childClosed(target) { - AddonManager.webAPI.clearInstallsFrom(target); - this._removeAddonListener(target); - }, - - sendEvent(mm, data) { - mm.sendAsyncMessage(MSG_INSTALL_EVENT, data); - }, - - classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"), - _xpcom_factory: { - createInstance: function(aOuter, aIid) { - if (aOuter != null) - throw Components.Exception("Component does not support aggregation", - Cr.NS_ERROR_NO_AGGREGATION); - - if (!gSingleton) - gSingleton = new amManager(); - return gSingleton.QueryInterface(aIid); - } - }, - QueryInterface: XPCOMUtils.generateQI([Ci.amIAddonManager, - Ci.amIWebInstaller, - Ci.nsITimerCallback, - Ci.nsIObserver, - Ci.nsIMessageListener]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amManager]); diff --git a/toolkit/mozapps/extensions/amContentHandler.js b/toolkit/mozapps/extensions/amContentHandler.js deleted file mode 100644 index 8dc4dfecd..000000000 --- a/toolkit/mozapps/extensions/amContentHandler.js +++ /dev/null @@ -1,100 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -const XPI_CONTENT_TYPE = "application/x-xpinstall"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -function amContentHandler() { -} - -amContentHandler.prototype = { - /** - * Handles a new request for an application/x-xpinstall file. - * - * @param aMimetype - * The mimetype of the file - * @param aContext - * The context passed to nsIChannel.asyncOpen - * @param aRequest - * The nsIRequest dealing with the content - */ - handleContent: function(aMimetype, aContext, aRequest) { - if (aMimetype != XPI_CONTENT_TYPE) - throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; - - if (!(aRequest instanceof Ci.nsIChannel)) - throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; - - let uri = aRequest.URI; - - let window = null; - let callbacks = aRequest.notificationCallbacks ? - aRequest.notificationCallbacks : - aRequest.loadGroup.notificationCallbacks; - if (callbacks) - window = callbacks.getInterface(Ci.nsIDOMWindow); - - aRequest.cancel(Cr.NS_BINDING_ABORTED); - - let installs = { - uris: [uri.spec], - hashes: [null], - names: [null], - icons: [null], - mimetype: XPI_CONTENT_TYPE, - triggeringPrincipal: aRequest.loadInfo.triggeringPrincipal, - callbackID: -1 - }; - - if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { - // When running in the main process this might be a frame inside an - // in-content UI page, walk up to find the first frame element in a chrome - // privileged document - let element = window.frameElement; - let ssm = Services.scriptSecurityManager; - while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) - element = element.ownerDocument.defaultView.frameElement; - - if (element) { - let listener = Cc["@mozilla.org/addons/integration;1"]. - getService(Ci.nsIMessageListener); - listener.wrappedJSObject.receiveMessage({ - name: MSG_INSTALL_ADDONS, - target: element, - data: installs, - }); - return; - } - } - - // Fall back to sending through the message manager - let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIContentFrameMessageManager); - - messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs); - }, - - classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]), - - log : function(aMsg) { - let msg = "amContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg); - Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService). - logStringMessage(msg); - dump(msg + "\n"); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amContentHandler]); diff --git a/toolkit/mozapps/extensions/amIAddonManager.idl b/toolkit/mozapps/extensions/amIAddonManager.idl deleted file mode 100644 index 58a58b62d..000000000 --- a/toolkit/mozapps/extensions/amIAddonManager.idl +++ /dev/null @@ -1,29 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIURI; - -/** - * A service to make some AddonManager functionality available to C++ callers. - * Javascript callers should still use AddonManager.jsm directly. - */ -[scriptable, function, uuid(7b45d82d-7ad5-48d7-9b05-f32eb9818cd4)] -interface amIAddonManager : nsISupports -{ - /** - * Synchronously map a URI to the corresponding Addon ID. - * - * Mappable URIs are limited to in-application resources belonging to the - * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. - * but do not include URIs from meta data, such as the add-on homepage. - * - * @param aURI - * The nsIURI to map - * @return - * true if the URI has been mapped successfully to an Addon ID - */ - boolean mapURIToAddonID(in nsIURI aURI, out AUTF8String aID); -}; diff --git a/toolkit/mozapps/extensions/amIAddonPathService.idl b/toolkit/mozapps/extensions/amIAddonPathService.idl deleted file mode 100644 index 9c9197a61..000000000 --- a/toolkit/mozapps/extensions/amIAddonPathService.idl +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIURI; - -/** - * This service maps file system paths where add-ons reside to the ID - * of the add-on. Paths are added by the add-on manager. They can - * looked up by anyone. - */ -[scriptable, uuid(fcd9e270-dfb1-11e3-8b68-0800200c9a66)] -interface amIAddonPathService : nsISupports -{ - /** - * Given a path to a file, return the ID of the add-on that the file belongs - * to. Returns an empty string if there is no add-on there. Note that if an - * add-on is located at /a/b/c, then looking up the path /a/b/c/d will return - * that add-on. - */ - AString findAddonId(in AString path); - - /** - * Call this function to inform the service that the given file system path is - * associated with the given add-on ID. - */ - void insertPath(in AString path, in AString addonId); - - /** - * Given a URI to a file, return the ID of the add-on that the file belongs - * to. Returns an empty string if there is no add-on there. - */ - AString mapURIToAddonId(in nsIURI aURI); -}; diff --git a/toolkit/mozapps/extensions/amIWebInstallListener.idl b/toolkit/mozapps/extensions/amIWebInstallListener.idl deleted file mode 100644 index eed108097..000000000 --- a/toolkit/mozapps/extensions/amIWebInstallListener.idl +++ /dev/null @@ -1,134 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIDOMElement; -interface nsIURI; -interface nsIVariant; - -/** - * amIWebInstallInfo is used by the default implementation of - * amIWebInstallListener to communicate with the running application and allow - * it to warn the user about blocked installs and start the installs running. - */ -[scriptable, uuid(fa0b47a3-f819-47ac-bc66-4bd1d7f67b1d)] -interface amIWebInstallInfo : nsISupports -{ - readonly attribute nsIDOMElement browser; - readonly attribute nsIURI originatingURI; - readonly attribute nsIVariant installs; - - /** - * Starts all installs. - */ - void install(); -}; - -/** - * The registered amIWebInstallListener is used to notify about new installs - * triggered by websites. The default implementation displays a confirmation - * dialog when add-ons are ready to install and uses the observer service to - * notify when installations are blocked. - */ -[scriptable, uuid(d9240d4b-6b3a-4cad-b402-de6c93337e0c)] -interface amIWebInstallListener : nsISupports -{ - /** - * Called when installation by websites is currently disabled. - * - * @param aBrowser - * The browser that triggered the installs - * @param aUri - * The URI of the site that triggered the installs - * @param aInstalls - * The AddonInstalls that were blocked - * @param aCount - * The number of AddonInstalls - */ - void onWebInstallDisabled(in nsIDOMElement aBrowser, in nsIURI aUri, - [array, size_is(aCount)] in nsIVariant aInstalls, - [optional] in uint32_t aCount); - - /** - * Called when the website is not allowed to directly prompt the user to - * install add-ons. - * - * @param aBrowser - * The browser that triggered the installs - * @param aUri - * The URI of the site that triggered the installs - * @param aInstalls - * The AddonInstalls that were blocked - * @param aCount - * The number of AddonInstalls - * @return true if the caller should start the installs - */ - boolean onWebInstallBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, - [array, size_is(aCount)] in nsIVariant aInstalls, - [optional] in uint32_t aCount); - - /** - * Called when a website wants to ask the user to install add-ons. - * - * @param aBrowser - * The browser that triggered the installs - * @param aUri - * The URI of the site that triggered the installs - * @param aInstalls - * The AddonInstalls that were requested - * @param aCount - * The number of AddonInstalls - * @return true if the caller should start the installs - */ - boolean onWebInstallRequested(in nsIDOMElement aBrowser, in nsIURI aUri, - [array, size_is(aCount)] in nsIVariant aInstalls, - [optional] in uint32_t aCount); -}; - -[scriptable, uuid(a80b89ad-bb1a-4c43-9cb7-3ae656556f78)] -interface amIWebInstallListener2 : nsISupports -{ - /** - * Called when a non-same-origin resource attempted to initiate an install. - * Installs will have already been cancelled and cannot be restarted. - * - * @param aBrowser - * The browser that triggered the installs - * @param aUri - * The URI of the site that triggered the installs - * @param aInstalls - * The AddonInstalls that were blocked - * @param aCount - * The number of AddonInstalls - */ - boolean onWebInstallOriginBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, - [array, size_is(aCount)] in nsIVariant aInstalls, - [optional] in uint32_t aCount); -}; - -/** - * amIWebInstallPrompt is used, if available, by the default implementation of - * amIWebInstallInfo to display a confirmation UI to the user before running - * installs. - */ -[scriptable, uuid(386906f1-4d18-45bf-bc81-5dcd68e42c3b)] -interface amIWebInstallPrompt : nsISupports -{ - /** - * Get a confirmation that the user wants to start the installs. - * - * @param aBrowser - * The browser that triggered the installs - * @param aUri - * The URI of the site that triggered the installs - * @param aInstalls - * The AddonInstalls that were requested - * @param aCount - * The number of AddonInstalls - */ - void confirm(in nsIDOMElement aBrowser, in nsIURI aUri, - [array, size_is(aCount)] in nsIVariant aInstalls, - [optional] in uint32_t aCount); -}; diff --git a/toolkit/mozapps/extensions/amIWebInstaller.idl b/toolkit/mozapps/extensions/amIWebInstaller.idl deleted file mode 100644 index 6c5ebca67..000000000 --- a/toolkit/mozapps/extensions/amIWebInstaller.idl +++ /dev/null @@ -1,82 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIDOMElement; -interface nsIVariant; -interface nsIURI; - -/** - * A callback function used to notify webpages when a requested install has - * ended. - * - * NOTE: This is *not* the same as InstallListener. - */ -[scriptable, function, uuid(bb22f5c0-3ca1-48f6-873c-54e87987700f)] -interface amIInstallCallback : nsISupports -{ - /** - * Called when an install completes or fails. - * - * @param aUrl - * The url of the add-on being installed - * @param aStatus - * 0 if the install was successful or negative if not - */ - void onInstallEnded(in AString aUrl, in int32_t aStatus); -}; - - -/** - * This interface is used to allow webpages to start installing add-ons. - */ -[scriptable, uuid(658d6c09-15e0-4688-bee8-8551030472a9)] -interface amIWebInstaller : nsISupports -{ - /** - * Checks if installation is enabled for a webpage. - * - * @param aMimetype - * The mimetype for the add-on to be installed - * @param referer - * The URL of the webpage trying to install an add-on - * @return true if installation is enabled - */ - boolean isInstallEnabled(in AString aMimetype, in nsIURI aReferer); - - /** - * Installs an array of add-ons at the request of a webpage - * - * @param aMimetype - * The mimetype for the add-ons - * @param aBrowser - * The browser installing the add-ons. - * @param aReferer - * The URI for the webpage installing the add-ons - * @param aUris - * The URIs of add-ons to be installed - * @param aHashes - * The hashes for the add-ons to be installed - * @param aNames - * The names for the add-ons to be installed - * @param aIcons - * The icons for the add-ons to be installed - * @param aCallback - * An optional callback to notify about installation success and - * failure - * @param aInstallCount - * An optional argument including the number of add-ons to install - * @return true if the installation was successfully started - */ - boolean installAddonsFromWebpage(in AString aMimetype, - in nsIDOMElement aBrowser, - in nsIURI aReferer, - [array, size_is(aInstallCount)] in wstring aUris, - [array, size_is(aInstallCount)] in wstring aHashes, - [array, size_is(aInstallCount)] in wstring aNames, - [array, size_is(aInstallCount)] in wstring aIcons, - [optional] in amIInstallCallback aCallback, - [optional] in uint32_t aInstallCount); -}; diff --git a/toolkit/mozapps/extensions/amInstallTrigger.js b/toolkit/mozapps/extensions/amInstallTrigger.js deleted file mode 100644 index 382791d32..000000000 --- a/toolkit/mozapps/extensions/amInstallTrigger.js +++ /dev/null @@ -1,240 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); - -const XPINSTALL_MIMETYPE = "application/x-xpinstall"; - -const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; -const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; -const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; - - -var log = Log.repository.getLogger("AddonManager.InstallTrigger"); -log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"]; - -function CallbackObject(id, callback, urls, mediator) { - this.id = id; - this.callback = callback; - this.urls = new Set(urls); - this.callCallback = function(url, status) { - try { - this.callback(url, status); - } - catch (e) { - log.warn("InstallTrigger callback threw an exception: " + e); - } - - this.urls.delete(url); - if (this.urls.size == 0) - mediator._callbacks.delete(id); - }; -} - -function RemoteMediator(window) { - window.QueryInterface(Ci.nsIInterfaceRequestor); - let utils = window.getInterface(Ci.nsIDOMWindowUtils); - this._windowID = utils.currentInnerWindowID; - - this.mm = window - .getInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIContentFrameMessageManager); - this.mm.addWeakMessageListener(MSG_INSTALL_CALLBACK, this); - - this._lastCallbackID = 0; - this._callbacks = new Map(); -} - -RemoteMediator.prototype = { - receiveMessage: function(message) { - if (message.name == MSG_INSTALL_CALLBACK) { - let payload = message.data; - let callbackHandler = this._callbacks.get(payload.callbackID); - if (callbackHandler) { - callbackHandler.callCallback(payload.url, payload.status); - } - } - }, - - enabled: function(url) { - let params = { - mimetype: XPINSTALL_MIMETYPE - }; - return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0]; - }, - - install: function(installs, principal, callback, window) { - let callbackID = this._addCallback(callback, installs.uris); - - installs.mimetype = XPINSTALL_MIMETYPE; - installs.triggeringPrincipal = principal; - installs.callbackID = callbackID; - - if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { - // When running in the main process this might be a frame inside an - // in-content UI page, walk up to find the first frame element in a chrome - // privileged document - let element = window.frameElement; - let ssm = Services.scriptSecurityManager; - while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) - element = element.ownerDocument.defaultView.frameElement; - - if (element) { - let listener = Cc["@mozilla.org/addons/integration;1"]. - getService(Ci.nsIMessageListener); - return listener.wrappedJSObject.receiveMessage({ - name: MSG_INSTALL_ADDONS, - target: element, - data: installs, - }); - } - } - - // Fall back to sending through the message manager - let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIContentFrameMessageManager); - - return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs)[0]; - }, - - _addCallback: function(callback, urls) { - if (!callback || typeof callback != "function") - return -1; - - let callbackID = this._windowID + "-" + ++this._lastCallbackID; - let callbackObject = new CallbackObject(callbackID, callback, urls, this); - this._callbacks.set(callbackID, callbackObject); - return callbackID; - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]) -}; - - -function InstallTrigger() { -} - -InstallTrigger.prototype = { - // Here be magic. We've declared ourselves as providing the - // nsIDOMGlobalPropertyInitializer interface, and are registered in the - // "JavaScript-global-property" category in the XPCOM category manager. This - // means that for newly created windows, XPCOM will createinstance this - // object, and then call init, passing in the window for which we need to - // provide an instance. We then initialize ourselves and return the webidl - // version of this object using the webidl-provided _create method, which - // XPCOM will then duly expose as a property value on the window. All this - // indirection is necessary because webidl does not (yet) support statics - // (bug 863952). See bug 926712 for more details about this implementation. - init: function(window) { - this._window = window; - this._principal = window.document.nodePrincipal; - this._url = window.document.documentURIObject; - - try { - this._mediator = new RemoteMediator(window); - } catch (ex) { - // If we can't set up IPC (e.g., because this is a top-level window - // or something), then don't expose InstallTrigger. - return null; - } - - return window.InstallTriggerImpl._create(window, this); - }, - - enabled: function() { - return this._mediator.enabled(this._url.spec); - }, - - updateEnabled: function() { - return this.enabled(); - }, - - install: function(installs, callback) { - let installData = { - uris: [], - hashes: [], - names: [], - icons: [], - }; - - for (let name of Object.keys(installs)) { - let item = installs[name]; - if (typeof item === "string") { - item = { URL: item }; - } - if (!item.URL) { - throw new this._window.Error("Missing URL property for '" + name + "'"); - } - - let url = this._resolveURL(item.URL); - if (!this._checkLoadURIFromScript(url)) { - throw new this._window.Error("Insufficient permissions to install: " + url.spec); - } - - let iconUrl = null; - if (item.IconURL) { - iconUrl = this._resolveURL(item.IconURL); - if (!this._checkLoadURIFromScript(iconUrl)) { - iconUrl = null; // If page can't load the icon, just ignore it - } - } - - installData.uris.push(url.spec); - installData.hashes.push(item.Hash || null); - installData.names.push(name); - installData.icons.push(iconUrl ? iconUrl.spec : null); - } - - return this._mediator.install(installData, this._principal, callback, this._window); - }, - - startSoftwareUpdate: function(url, flags) { - let filename = Services.io.newURI(url, null, null) - .QueryInterface(Ci.nsIURL) - .filename; - let args = {}; - args[filename] = { "URL": url }; - return this.install(args); - }, - - installChrome: function(type, url, skin) { - return this.startSoftwareUpdate(url); - }, - - _resolveURL: function(url) { - return Services.io.newURI(url, null, this._url); - }, - - _checkLoadURIFromScript: function(uri) { - let secman = Services.scriptSecurityManager; - try { - secman.checkLoadURIWithPrincipal(this._principal, - uri, - secman.DISALLOW_INHERIT_PRINCIPAL); - return true; - } - catch (e) { - return false; - } - }, - - classID: Components.ID("{9df8ef2b-94da-45c9-ab9f-132eb55fddf1}"), - contractID: "@mozilla.org/addons/installtrigger;1", - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIDOMGlobalPropertyInitializer]) -}; - - - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InstallTrigger]); diff --git a/toolkit/mozapps/extensions/amWebAPI.js b/toolkit/mozapps/extensions/amWebAPI.js deleted file mode 100644 index 5ad0d23f1..000000000 --- a/toolkit/mozapps/extensions/amWebAPI.js +++ /dev/null @@ -1,269 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - -const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest"; -const MSG_PROMISE_RESULT = "WebAPIPromiseResult"; -const MSG_INSTALL_EVENT = "WebAPIInstallEvent"; -const MSG_INSTALL_CLEANUP = "WebAPICleanup"; -const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest"; -const MSG_ADDON_EVENT = "WebAPIAddonEvent"; - -class APIBroker { - constructor(mm) { - this.mm = mm; - - this._promises = new Map(); - - // _installMap maps integer ids to DOM AddonInstall instances - this._installMap = new Map(); - - this.mm.addMessageListener(MSG_PROMISE_RESULT, this); - this.mm.addMessageListener(MSG_INSTALL_EVENT, this); - - this._eventListener = null; - } - - receiveMessage(message) { - let payload = message.data; - - switch (message.name) { - case MSG_PROMISE_RESULT: { - if (!this._promises.has(payload.callbackID)) { - return; - } - - let resolve = this._promises.get(payload.callbackID); - this._promises.delete(payload.callbackID); - resolve(payload); - break; - } - - case MSG_INSTALL_EVENT: { - let install = this._installMap.get(payload.id); - if (!install) { - let err = new Error(`Got install event for unknown install ${payload.id}`); - Cu.reportError(err); - return; - } - install._dispatch(payload); - break; - } - - case MSG_ADDON_EVENT: { - if (this._eventListener) { - this._eventListener(payload); - } - } - } - } - - sendRequest(type, ...args) { - return new Promise(resolve => { - let callbackID = APIBroker._nextID++; - - this._promises.set(callbackID, resolve); - this.mm.sendAsyncMessage(MSG_PROMISE_REQUEST, { type, callbackID, args }); - }); - } - - setAddonListener(callback) { - this._eventListener = callback; - if (callback) { - this.mm.addMessageListener(MSG_ADDON_EVENT, this); - this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: true}); - } else { - this.mm.removeMessageListener(MSG_ADDON_EVENT, this); - this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: false}); - } - } - - sendCleanup(ids) { - this.setAddonListener(null); - this.mm.sendAsyncMessage(MSG_INSTALL_CLEANUP, { ids }); - } -} - -APIBroker._nextID = 0; - -// Base class for building classes to back content-exposed interfaces. -class APIObject { - init(window, broker, properties) { - this.window = window; - this.broker = broker; - - // Copy any provided properties onto this object, webidl bindings - // will only expose to content what should be exposed. - for (let key of Object.keys(properties)) { - this[key] = properties[key]; - } - } - - /** - * Helper to implement an asychronous method visible to content, where - * the method is implemented by sending a message to the parent process - * and then wrapping the returned object or error in an appropriate object. - * This helper method ensures that: - * - Returned Promise objects are from the content window - * - Rejected Promises have Error objects from the content window - * - Only non-internal errors are exposed to the caller - * - * @param {string} apiRequest The command to invoke in the parent process. - * @param {array} apiArgs The arguments to include with the - * request to the parent process. - * @param {function} resultConvert If provided, a function called with the - * result from the parent process as an - * argument. Used to convert the result - * into something appropriate for content. - * @returns {Promise} A Promise suitable for passing directly to content. - */ - _apiTask(apiRequest, apiArgs, resultConverter) { - let win = this.window; - let broker = this.broker; - return new win.Promise((resolve, reject) => { - Task.spawn(function*() { - let result = yield broker.sendRequest(apiRequest, ...apiArgs); - if ("reject" in result) { - let err = new win.Error(result.reject.message); - // We don't currently put any other properties onto Errors - // generated by mozAddonManager. If/when we do, they will - // need to get copied here. - reject(err); - return; - } - - let obj = result.resolve; - if (resultConverter) { - obj = resultConverter(obj); - } - resolve(obj); - }).catch(err => { - Cu.reportError(err); - reject(new win.Error("Unexpected internal error")); - }); - }); - } -} - -class Addon extends APIObject { - constructor(...args) { - super(); - this.init(...args); - } - - uninstall() { - return this._apiTask("addonUninstall", [this.id]); - } - - setEnabled(value) { - return this._apiTask("addonSetEnabled", [this.id, value]); - } -} - -class AddonInstall extends APIObject { - constructor(window, broker, properties) { - super(); - this.init(window, broker, properties); - - broker._installMap.set(properties.id, this); - } - - _dispatch(data) { - // The message for the event includes updated copies of all install - // properties. Use the usual "let webidl filter visible properties" trick. - for (let key of Object.keys(data)) { - this[key] = data[key]; - } - - let event = new this.window.Event(data.event); - this.__DOM_IMPL__.dispatchEvent(event); - } - - install() { - return this._apiTask("addonInstallDoInstall", [this.id]); - } - - cancel() { - return this._apiTask("addonInstallCancel", [this.id]); - } -} - -class WebAPI extends APIObject { - constructor() { - super(); - this.allInstalls = []; - this.listenerCount = 0; - } - - init(window) { - let mm = window - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIContentFrameMessageManager); - let broker = new APIBroker(mm); - - super.init(window, broker, {}); - - window.addEventListener("unload", event => { - this.broker.sendCleanup(this.allInstalls); - }); - } - - getAddonByID(id) { - return this._apiTask("getAddonByID", [id], addonInfo => { - if (!addonInfo) { - return null; - } - let addon = new Addon(this.window, this.broker, addonInfo); - return this.window.Addon._create(this.window, addon); - }); - } - - createInstall(options) { - return this._apiTask("createInstall", [options], installInfo => { - if (!installInfo) { - return null; - } - let install = new AddonInstall(this.window, this.broker, installInfo); - this.allInstalls.push(installInfo.id); - return this.window.AddonInstall._create(this.window, install); - }); - } - - eventListenerWasAdded(type) { - if (this.listenerCount == 0) { - this.broker.setAddonListener(data => { - let event = new this.window.AddonEvent(data.event, data); - this.__DOM_IMPL__.dispatchEvent(event); - }); - } - this.listenerCount++; - } - - eventListenerWasRemoved(type) { - this.listenerCount--; - if (this.listenerCount == 0) { - this.broker.setAddonListener(null); - } - } - - QueryInterface(iid) { - if (iid.equals(WebAPI.classID) || iid.equals(Ci.nsISupports) - || iid.equals(Ci.nsIDOMGlobalPropertyInitializer)) { - return this; - } - return Cr.NS_ERROR_NO_INTERFACE; - } -} - -WebAPI.prototype.classID = Components.ID("{8866d8e3-4ea5-48b7-a891-13ba0ac15235}"); -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebAPI]); diff --git a/toolkit/mozapps/extensions/amWebInstallListener.js b/toolkit/mozapps/extensions/amWebInstallListener.js deleted file mode 100644 index 0bcc345e8..000000000 --- a/toolkit/mozapps/extensions/amWebInstallListener.js +++ /dev/null @@ -1,348 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This is a default implementation of amIWebInstallListener that should work - * for most applications but can be overriden. It notifies the observer service - * about blocked installs. For normal installs it pops up an install - * confirmation when all the add-ons have been downloaded. - */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Preferences.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PromptUtils", "resource://gre/modules/SharedPromptUtils.jsm"); - -const URI_XPINSTALL_DIALOG = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; - -// Installation can begin from any of these states -const READY_STATES = [ - AddonManager.STATE_AVAILABLE, - AddonManager.STATE_DOWNLOAD_FAILED, - AddonManager.STATE_INSTALL_FAILED, - AddonManager.STATE_CANCELLED -]; - -Cu.import("resource://gre/modules/Log.jsm"); -const LOGGER_ID = "addons.weblistener"; - -// Create a new logger for use by the Addons Web Listener -// (Requires AddonManager.jsm) -var logger = Log.repository.getLogger(LOGGER_ID); - -function notifyObservers(aTopic, aBrowser, aUri, aInstalls) { - let info = { - browser: aBrowser, - originatingURI: aUri, - installs: aInstalls, - - QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) - }; - Services.obs.notifyObservers(info, aTopic, null); -} - -/** - * Creates a new installer to monitor downloads and prompt to install when - * ready - * - * @param aBrowser - * The browser that started the installations - * @param aUrl - * The URL that started the installations - * @param aInstalls - * An array of AddonInstalls - */ -function Installer(aBrowser, aUrl, aInstalls) { - this.browser = aBrowser; - this.url = aUrl; - this.downloads = aInstalls; - this.installed = []; - - notifyObservers("addon-install-started", aBrowser, aUrl, aInstalls); - - for (let install of aInstalls) { - install.addListener(this); - - // Start downloading if it hasn't already begun - if (READY_STATES.indexOf(install.state) != -1) - install.install(); - } - - this.checkAllDownloaded(); -} - -Installer.prototype = { - browser: null, - downloads: null, - installed: null, - isDownloading: true, - - /** - * Checks if all downloads are now complete and if so prompts to install. - */ - checkAllDownloaded: function() { - // Prevent re-entrancy caused by the confirmation dialog cancelling unwanted - // installs. - if (!this.isDownloading) - return; - - var failed = []; - var installs = []; - - for (let install of this.downloads) { - switch (install.state) { - case AddonManager.STATE_AVAILABLE: - case AddonManager.STATE_DOWNLOADING: - // Exit early if any add-ons haven't started downloading yet or are - // still downloading - return; - case AddonManager.STATE_DOWNLOAD_FAILED: - failed.push(install); - break; - case AddonManager.STATE_DOWNLOADED: - // App disabled items are not compatible and so fail to install - if (install.addon.appDisabled) - failed.push(install); - else - installs.push(install); - - if (install.linkedInstalls) { - for (let linkedInstall of install.linkedInstalls) { - linkedInstall.addListener(this); - // Corrupt or incompatible items fail to install - if (linkedInstall.state == AddonManager.STATE_DOWNLOAD_FAILED || linkedInstall.addon.appDisabled) - failed.push(linkedInstall); - else - installs.push(linkedInstall); - } - } - break; - case AddonManager.STATE_CANCELLED: - // Just ignore cancelled downloads - break; - default: - logger.warn("Download of " + install.sourceURI.spec + " in unexpected state " + - install.state); - } - } - - this.isDownloading = false; - this.downloads = installs; - - if (failed.length > 0) { - // Stop listening and cancel any installs that are failed because of - // compatibility reasons. - for (let install of failed) { - if (install.state == AddonManager.STATE_DOWNLOADED) { - install.removeListener(this); - install.cancel(); - } - } - notifyObservers("addon-install-failed", this.browser, this.url, failed); - } - - // If none of the downloads were successful then exit early - if (this.downloads.length == 0) - return; - - // Check for a custom installation prompt that may be provided by the - // applicaton - if ("@mozilla.org/addons/web-install-prompt;1" in Cc) { - try { - let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"]. - getService(Ci.amIWebInstallPrompt); - prompt.confirm(this.browser, this.url, this.downloads, this.downloads.length); - return; - } - catch (e) {} - } - - if (Preferences.get("xpinstall.customConfirmationUI", false)) { - notifyObservers("addon-install-confirmation", this.browser, this.url, this.downloads); - return; - } - - let args = {}; - args.url = this.url; - args.installs = this.downloads; - args.wrappedJSObject = args; - - try { - Cc["@mozilla.org/base/telemetry;1"]. - getService(Ci.nsITelemetry). - getHistogramById("SECURITY_UI"). - add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL); - let parentWindow = null; - if (this.browser) { - parentWindow = this.browser.ownerDocument.defaultView; - PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", this.browser); - } - Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG, - null, "chrome,modal,centerscreen", args); - } catch (e) { - logger.warn("Exception showing install confirmation dialog", e); - for (let install of this.downloads) { - install.removeListener(this); - // Cancel the installs, as currently there is no way to make them fail - // from here. - install.cancel(); - } - notifyObservers("addon-install-cancelled", this.browser, this.url, - this.downloads); - } - }, - - /** - * Checks if all installs are now complete and if so notifies observers. - */ - checkAllInstalled: function() { - var failed = []; - - for (let install of this.downloads) { - switch (install.state) { - case AddonManager.STATE_DOWNLOADED: - case AddonManager.STATE_INSTALLING: - // Exit early if any add-ons haven't started installing yet or are - // still installing - return; - case AddonManager.STATE_INSTALL_FAILED: - failed.push(install); - break; - } - } - - this.downloads = null; - - if (failed.length > 0) - notifyObservers("addon-install-failed", this.browser, this.url, failed); - - if (this.installed.length > 0) - notifyObservers("addon-install-complete", this.browser, this.url, this.installed); - this.installed = null; - }, - - onDownloadCancelled: function(aInstall) { - aInstall.removeListener(this); - this.checkAllDownloaded(); - }, - - onDownloadFailed: function(aInstall) { - aInstall.removeListener(this); - this.checkAllDownloaded(); - }, - - onDownloadEnded: function(aInstall) { - this.checkAllDownloaded(); - return false; - }, - - onInstallCancelled: function(aInstall) { - aInstall.removeListener(this); - this.checkAllInstalled(); - }, - - onInstallFailed: function(aInstall) { - aInstall.removeListener(this); - this.checkAllInstalled(); - }, - - onInstallEnded: function(aInstall) { - aInstall.removeListener(this); - this.installed.push(aInstall); - - // If installing a theme that is disabled and can be enabled then enable it - if (aInstall.addon.type == "theme" && - aInstall.addon.userDisabled == true && - aInstall.addon.appDisabled == false) { - aInstall.addon.userDisabled = false; - } - - this.checkAllInstalled(); - } -}; - -function extWebInstallListener() { -} - -extWebInstallListener.prototype = { - /** - * @see amIWebInstallListener.idl - */ - onWebInstallDisabled: function(aBrowser, aUri, aInstalls) { - let info = { - browser: aBrowser, - originatingURI: aUri, - installs: aInstalls, - - QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) - }; - Services.obs.notifyObservers(info, "addon-install-disabled", null); - }, - - /** - * @see amIWebInstallListener.idl - */ - onWebInstallOriginBlocked: function(aBrowser, aUri, aInstalls) { - let info = { - browser: aBrowser, - originatingURI: aUri, - installs: aInstalls, - - install: function() { - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) - }; - Services.obs.notifyObservers(info, "addon-install-origin-blocked", null); - - return false; - }, - - /** - * @see amIWebInstallListener.idl - */ - onWebInstallBlocked: function(aBrowser, aUri, aInstalls) { - let info = { - browser: aBrowser, - originatingURI: aUri, - installs: aInstalls, - - install: function() { - new Installer(this.browser, this.originatingURI, this.installs); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) - }; - Services.obs.notifyObservers(info, "addon-install-blocked", null); - - return false; - }, - - /** - * @see amIWebInstallListener.idl - */ - onWebInstallRequested: function(aBrowser, aUri, aInstalls) { - new Installer(aBrowser, aUri, aInstalls); - - // We start the installs ourself - return false; - }, - - classDescription: "XPI Install Handler", - contractID: "@mozilla.org/addons/web-install-listener;1", - classID: Components.ID("{0f38e086-89a3-40a5-8ffc-9b694de1d04a}"), - QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallListener, - Ci.amIWebInstallListener2]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([extWebInstallListener]); diff --git a/toolkit/mozapps/extensions/content/OpenH264-license.txt b/toolkit/mozapps/extensions/content/OpenH264-license.txt deleted file mode 100644 index ad37989b8..000000000 --- a/toolkit/mozapps/extensions/content/OpenH264-license.txt +++ /dev/null @@ -1,59 +0,0 @@ -------------------------------------------------------- -About The Cisco-Provided Binary of OpenH264 Video Codec -------------------------------------------------------- - -Cisco provides this program under the terms of the BSD license. - -Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. - -As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. - -For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary - -A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org - ------------ -BSD License ------------ - -Copyright © 2014 Cisco Systems, Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------ -AVC/H.264 Patent Portfolio License Notice ------------------------------------------ - -The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: - -THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM - -Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla - ---------------------------------------------- -AVC/H.264 Patent Portfolio License Conditions ---------------------------------------------- - -In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met: - -1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device; - -2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary; - -3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text: - - "OpenH264 Video Codec provided by Cisco Systems, Inc." - -4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. - - - - v1.0 diff --git a/toolkit/mozapps/extensions/content/about.js b/toolkit/mozapps/extensions/content/about.js deleted file mode 100644 index 4f8fb353e..000000000 --- a/toolkit/mozapps/extensions/content/about.js +++ /dev/null @@ -1,103 +0,0 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* import-globals-from ../../../content/contentAreaUtils.js */ - -var Cu = Components.utils; -Cu.import("resource://gre/modules/AddonManager.jsm"); - -function init() { - var addon = window.arguments[0]; - var extensionsStrings = document.getElementById("extensionsStrings"); - - document.documentElement.setAttribute("addontype", addon.type); - - var iconURL = AddonManager.getPreferredIconURL(addon, 48, window); - if (iconURL) { - var extensionIcon = document.getElementById("extensionIcon"); - extensionIcon.src = iconURL; - } - - document.title = extensionsStrings.getFormattedString("aboutWindowTitle", [addon.name]); - var extensionName = document.getElementById("extensionName"); - extensionName.textContent = addon.name; - - var extensionVersion = document.getElementById("extensionVersion"); - if (addon.version) - extensionVersion.setAttribute("value", extensionsStrings.getFormattedString("aboutWindowVersionString", [addon.version])); - else - extensionVersion.hidden = true; - - var extensionDescription = document.getElementById("extensionDescription"); - if (addon.description) - extensionDescription.textContent = addon.description; - else - extensionDescription.hidden = true; - - var numDetails = 0; - - var extensionCreator = document.getElementById("extensionCreator"); - if (addon.creator) { - extensionCreator.setAttribute("value", addon.creator); - numDetails++; - } else { - extensionCreator.hidden = true; - var extensionCreatorLabel = document.getElementById("extensionCreatorLabel"); - extensionCreatorLabel.hidden = true; - } - - var extensionHomepage = document.getElementById("extensionHomepage"); - var homepageURL = addon.homepageURL; - if (homepageURL) { - extensionHomepage.setAttribute("homepageURL", homepageURL); - extensionHomepage.setAttribute("tooltiptext", homepageURL); - numDetails++; - } else { - extensionHomepage.hidden = true; - } - - numDetails += appendToList("extensionDevelopers", "developersBox", addon.developers); - numDetails += appendToList("extensionTranslators", "translatorsBox", addon.translators); - numDetails += appendToList("extensionContributors", "contributorsBox", addon.contributors); - - if (numDetails == 0) { - var groove = document.getElementById("groove"); - groove.hidden = true; - var extensionDetailsBox = document.getElementById("extensionDetailsBox"); - extensionDetailsBox.hidden = true; - } - - var acceptButton = document.documentElement.getButton("accept"); - acceptButton.label = extensionsStrings.getString("aboutWindowCloseButton"); - - setTimeout(sizeToContent, 0); -} - -function appendToList(aHeaderId, aNodeId, aItems) { - var header = document.getElementById(aHeaderId); - var node = document.getElementById(aNodeId); - - if (!aItems || aItems.length == 0) { - header.hidden = true; - return 0; - } - - for (let currentItem of aItems) { - var label = document.createElement("label"); - label.textContent = currentItem; - label.setAttribute("class", "contributor"); - node.appendChild(label); - } - - return aItems.length; -} - -function loadHomepage(aEvent) { - window.close(); - openURL(aEvent.target.getAttribute("homepageURL")); -} diff --git a/toolkit/mozapps/extensions/content/about.xul b/toolkit/mozapps/extensions/content/about.xul deleted file mode 100644 index 6effcf37a..000000000 --- a/toolkit/mozapps/extensions/content/about.xul +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - -

Test page for the discovery pane

-

Direct install

-

JS install

- - diff --git a/toolkit/mozapps/extensions/test/browser/head.js b/toolkit/mozapps/extensions/test/browser/head.js deleted file mode 100644 index 5a749099d..000000000 --- a/toolkit/mozapps/extensions/test/browser/head.js +++ /dev/null @@ -1,1468 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -/* globals end_test*/ - -Components.utils.import("resource://gre/modules/NetUtil.jsm"); - -var tmp = {}; -Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp); -Components.utils.import("resource://gre/modules/Log.jsm", tmp); -var AddonManager = tmp.AddonManager; -var AddonManagerPrivate = tmp.AddonManagerPrivate; -var Log = tmp.Log; - -var pathParts = gTestPath.split("/"); -// Drop the test filename -pathParts.splice(pathParts.length - 1, pathParts.length); - -var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]); - -// Drop the UI type -if (gTestInWindow) { - pathParts.splice(pathParts.length - 1, pathParts.length); -} - -const RELATIVE_DIR = pathParts.slice(4).join("/") + "/"; - -const TESTROOT = "http://example.com/" + RELATIVE_DIR; -const SECURE_TESTROOT = "https://example.com/" + RELATIVE_DIR; -const TESTROOT2 = "http://example.org/" + RELATIVE_DIR; -const SECURE_TESTROOT2 = "https://example.org/" + RELATIVE_DIR; -const CHROMEROOT = pathParts.join("/") + "/"; -const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; -const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; -const PREF_XPI_ENABLED = "xpinstall.enabled"; -const PREF_UPDATEURL = "extensions.update.url"; -const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; -const PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI = "xpinstall.customConfirmationUI"; -const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory"; - -const MANAGER_URI = "about:addons"; -const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; -const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; -const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults"; -const PREF_STRICT_COMPAT = "extensions.strictCompatibility"; - -var PREF_CHECK_COMPATIBILITY; -(function() { - var channel = "default"; - try { - channel = Services.prefs.getCharPref("app.update.channel"); - } catch (e) { } - if (channel != "aurora" && - channel != "beta" && - channel != "release" && - channel != "esr") { - var version = "nightly"; - } else { - version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1"); - } - PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version; -})(); - -var gPendingTests = []; -var gTestsRun = 0; -var gTestStart = null; - -var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window); - -var gRestorePrefs = [{name: PREF_LOGGING_ENABLED}, - {name: PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI}, - {name: "extensions.webservice.discoverURL"}, - {name: "extensions.update.url"}, - {name: "extensions.update.background.url"}, - {name: "extensions.update.enabled"}, - {name: "extensions.update.autoUpdateDefault"}, - {name: "extensions.getAddons.get.url"}, - {name: "extensions.getAddons.getWithPerformance.url"}, - {name: "extensions.getAddons.search.browseURL"}, - {name: "extensions.getAddons.search.url"}, - {name: "extensions.getAddons.cache.enabled"}, - {name: "devtools.chrome.enabled"}, - {name: PREF_SEARCH_MAXRESULTS}, - {name: PREF_STRICT_COMPAT}, - {name: PREF_CHECK_COMPATIBILITY}]; - -for (let pref of gRestorePrefs) { - if (!Services.prefs.prefHasUserValue(pref.name)) { - pref.type = "clear"; - continue; - } - pref.type = Services.prefs.getPrefType(pref.name); - if (pref.type == Services.prefs.PREF_BOOL) - pref.value = Services.prefs.getBoolPref(pref.name); - else if (pref.type == Services.prefs.PREF_INT) - pref.value = Services.prefs.getIntPref(pref.name); - else if (pref.type == Services.prefs.PREF_STRING) - pref.value = Services.prefs.getCharPref(pref.name); -} - -// Turn logging on for all tests -Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); - -Services.prefs.setBoolPref(PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI, false); - -// Helper to register test failures and close windows if any are left open -function checkOpenWindows(aWindowID) { - let windows = Services.wm.getEnumerator(aWindowID); - let found = false; - while (windows.hasMoreElements()) { - let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); - if (!win.closed) { - found = true; - win.close(); - } - } - if (found) - ok(false, "Found unexpected " + aWindowID + " window still open"); -} - -// Tools to disable and re-enable the background update and blocklist timers -// so that tests can protect themselves from unwanted timer events. -var gCatMan = Components.classes["@mozilla.org/categorymanager;1"] - .getService(Components.interfaces.nsICategoryManager); -// Default values from toolkit/mozapps/extensions/extensions.manifest, but disable*UpdateTimer() -// records the actual value so we can put it back in enable*UpdateTimer() -var backgroundUpdateConfig = "@mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400"; -var blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400"; - -var UTIMER = "update-timer"; -var AMANAGER = "addonManager"; -var BLOCKLIST = "nsBlocklistService"; - -function disableBackgroundUpdateTimer() { - info("Disabling " + UTIMER + " " + AMANAGER); - backgroundUpdateConfig = gCatMan.getCategoryEntry(UTIMER, AMANAGER); - gCatMan.deleteCategoryEntry(UTIMER, AMANAGER, true); -} - -function enableBackgroundUpdateTimer() { - info("Enabling " + UTIMER + " " + AMANAGER); - gCatMan.addCategoryEntry(UTIMER, AMANAGER, backgroundUpdateConfig, false, true); -} - -function disableBlocklistUpdateTimer() { - info("Disabling " + UTIMER + " " + BLOCKLIST); - blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST); - gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true); -} - -function enableBlocklistUpdateTimer() { - info("Enabling " + UTIMER + " " + BLOCKLIST); - gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true); -} - -registerCleanupFunction(function() { - // Restore prefs - for (let pref of gRestorePrefs) { - if (pref.type == "clear") - Services.prefs.clearUserPref(pref.name); - else if (pref.type == Services.prefs.PREF_BOOL) - Services.prefs.setBoolPref(pref.name, pref.value); - else if (pref.type == Services.prefs.PREF_INT) - Services.prefs.setIntPref(pref.name, pref.value); - else if (pref.type == Services.prefs.PREF_STRING) - Services.prefs.setCharPref(pref.name, pref.value); - } - - // Throw an error if the add-ons manager window is open anywhere - checkOpenWindows("Addons:Manager"); - checkOpenWindows("Addons:Compatibility"); - checkOpenWindows("Addons:Install"); - - return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve)) - .then(aInstalls => { - for (let install of aInstalls) { - if (install instanceof MockInstall) - continue; - - ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state); - install.cancel(); - } - }); -}); - -function log_exceptions(aCallback, ...aArgs) { - try { - return aCallback.apply(null, aArgs); - } - catch (e) { - info("Exception thrown: " + e); - throw e; - } -} - -function log_callback(aPromise, aCallback) { - aPromise.then(aCallback) - .then(null, e => info("Exception thrown: " + e)); - return aPromise; -} - -function add_test(test) { - gPendingTests.push(test); -} - -function run_next_test() { - // Make sure we're not calling run_next_test from inside an add_task() test - // We're inside the browser_test.js 'testScope' here - if (this.__tasks) { - throw new Error("run_next_test() called from an add_task() test function. " + - "run_next_test() should not be called from inside add_task() " + - "under any circumstances!"); - } - if (gTestsRun > 0) - info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms"); - - if (gPendingTests.length == 0) { - executeSoon(end_test); - return; - } - - gTestsRun++; - var test = gPendingTests.shift(); - if (test.name) - info("Running test " + gTestsRun + " (" + test.name + ")"); - else - info("Running test " + gTestsRun); - - gTestStart = Date.now(); - executeSoon(() => log_exceptions(test)); -} - -var get_tooltip_info = Task.async(function*(addon) { - let managerWindow = addon.ownerDocument.defaultView; - - // The popup code uses a triggering event's target to set the - // document.tooltipNode property. - let nameNode = addon.ownerDocument.getAnonymousElementByAttribute(addon, "anonid", "name"); - let event = new managerWindow.CustomEvent("TriggerEvent"); - nameNode.dispatchEvent(event); - - let tooltip = managerWindow.document.getElementById("addonitem-tooltip"); - - let promise = BrowserTestUtils.waitForEvent(tooltip, "popupshown"); - tooltip.openPopup(nameNode, "after_start", 0, 0, false, false, event); - yield promise; - - let tiptext = tooltip.label; - - promise = BrowserTestUtils.waitForEvent(tooltip, "popuphidden"); - tooltip.hidePopup(); - yield promise; - - let expectedName = addon.getAttribute("name"); - ok(tiptext.substring(0, expectedName.length), expectedName, - "Tooltip should always start with the expected name"); - - if (expectedName.length == tiptext.length) { - return { - name: tiptext, - version: undefined - }; - } - return { - name: tiptext.substring(0, expectedName.length), - version: tiptext.substring(expectedName.length + 1) - }; -}); - -function get_addon_file_url(aFilename) { - try { - var cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIChromeRegistry); - var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename)); - return fileurl.QueryInterface(Ci.nsIFileURL); - } catch (ex) { - var jar = getJar(CHROMEROOT + "addons/" + aFilename); - var tmpDir = extractJarToTmp(jar); - tmpDir.append(aFilename); - - return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL); - } -} - -function get_current_view(aManager) { - let view = aManager.document.getElementById("view-port").selectedPanel; - if (view.id == "headered-views") { - view = aManager.document.getElementById("headered-views-content").selectedPanel; - } - is(view, aManager.gViewController.displayedView, "view controller is tracking the displayed view correctly"); - return view; -} - -function get_test_items_in_list(aManager) { - var tests = "@tests.mozilla.org"; - - let view = get_current_view(aManager); - let listid = view.id == "search-view" ? "search-list" : "addon-list"; - let item = aManager.document.getElementById(listid).firstChild; - let items = []; - - while (item) { - if (item.localName != "richlistitem") { - item = item.nextSibling; - continue; - } - - if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests) - items.push(item); - item = item.nextSibling; - } - - return items; -} - -function check_all_in_list(aManager, aIds, aIgnoreExtras) { - var doc = aManager.document; - var view = get_current_view(aManager); - var listid = view.id == "search-view" ? "search-list" : "addon-list"; - var list = doc.getElementById(listid); - - var inlist = []; - var node = list.firstChild; - while (node) { - if (node.value) - inlist.push(node.value); - node = node.nextSibling; - } - - for (let id of aIds) { - if (inlist.indexOf(id) == -1) - ok(false, "Should find " + id + " in the list"); - } - - if (aIgnoreExtras) - return; - - for (let inlistItem of inlist) { - if (aIds.indexOf(inlistItem) == -1) - ok(false, "Shouldn't have seen " + inlistItem + " in the list"); - } -} - -function get_addon_element(aManager, aId) { - var doc = aManager.document; - var view = get_current_view(aManager); - var listid = "addon-list"; - if (view.id == "search-view") - listid = "search-list"; - else if (view.id == "updates-view") - listid = "updates-list"; - var list = doc.getElementById(listid); - - var node = list.firstChild; - while (node) { - if (node.value == aId) - return node; - node = node.nextSibling; - } - return null; -} - -function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) { - requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); - - if (!aForceWait && !aManagerWindow.gViewController.isLoading) { - log_exceptions(aCallback, aManagerWindow); - return; - } - - aManagerWindow.document.addEventListener("ViewChanged", function() { - aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false); - log_exceptions(aCallback, aManagerWindow); - }, false); -} - -function wait_for_manager_load(aManagerWindow, aCallback) { - if (!aManagerWindow.gIsInitializing) { - log_exceptions(aCallback, aManagerWindow); - return; - } - - info("Waiting for initialization"); - aManagerWindow.document.addEventListener("Initialized", function() { - aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false); - log_exceptions(aCallback, aManagerWindow); - }, false); -} - -function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) { - let p = new Promise((resolve, reject) => { - - function setup_manager(aManagerWindow) { - if (aLoadCallback) - log_exceptions(aLoadCallback, aManagerWindow); - - if (aView) - aManagerWindow.loadView(aView); - - ok(aManagerWindow != null, "Should have an add-ons manager window"); - is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI"); - - waitForFocus(function() { - info("window has focus, waiting for manager load"); - wait_for_manager_load(aManagerWindow, function() { - info("Manager waiting for view load"); - wait_for_view_load(aManagerWindow, function() { - resolve(aManagerWindow); - }, null, aLongerTimeout); - }); - }, aManagerWindow); - } - - if (gUseInContentUI) { - info("Loading manager window in tab"); - Services.obs.addObserver(function (aSubject, aTopic, aData) { - Services.obs.removeObserver(arguments.callee, aTopic); - if (aSubject.location.href != MANAGER_URI) { - info("Ignoring load event for " + aSubject.location.href); - return; - } - setup_manager(aSubject); - }, "EM-loaded", false); - - gBrowser.selectedTab = gBrowser.addTab(); - switchToTabHavingURI(MANAGER_URI, true); - } else { - info("Loading manager window in dialog"); - Services.obs.addObserver(function (aSubject, aTopic, aData) { - Services.obs.removeObserver(arguments.callee, aTopic); - setup_manager(aSubject); - }, "EM-loaded", false); - - openDialog(MANAGER_URI); - } - }); - - // The promise resolves with the manager window, so it is passed to the callback - return log_callback(p, aCallback); -} - -function close_manager(aManagerWindow, aCallback, aLongerTimeout) { - let p = new Promise((resolve, reject) => { - requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); - - ok(aManagerWindow != null, "Should have an add-ons manager window to close"); - is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI"); - - aManagerWindow.addEventListener("unload", function() { - try { - dump("Manager window unload handler\n"); - this.removeEventListener("unload", arguments.callee, false); - resolve(); - } catch (e) { - reject(e); - } - }, false); - }); - - info("Telling manager window to close"); - aManagerWindow.close(); - info("Manager window close() call returned"); - - return log_callback(p, aCallback); -} - -function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) { - if (!aManagerWindow) { - return open_manager(aView, aCallback, aLoadCallback); - } - - return close_manager(aManagerWindow) - .then(() => open_manager(aView, aCallback, aLoadCallback)); -} - -function wait_for_window_open(aCallback) { - Services.wm.addListener({ - onOpenWindow: function(aWindow) { - Services.wm.removeListener(this); - - let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - domwindow.addEventListener("load", function() { - domwindow.removeEventListener("load", arguments.callee, false); - executeSoon(function() { - aCallback(domwindow); - }); - }, false); - }, - - onCloseWindow: function(aWindow) { - }, - - onWindowTitleChange: function(aWindow, aTitle) { - } - }); -} - -function get_string(aName, ...aArgs) { - var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); - if (aArgs.length == 0) - return bundle.GetStringFromName(aName); - return bundle.formatStringFromName(aName, aArgs, aArgs.length); -} - -function formatDate(aDate) { - const locale = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry) - .getSelectedLocale("global", true); - const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' }; - return aDate.toLocaleDateString(locale, dtOptions); -} - -function is_hidden(aElement) { - var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, ""); - if (style.display == "none") - return true; - if (style.visibility != "visible") - return true; - - // Hiding a parent element will hide all its children - if (aElement.parentNode != aElement.ownerDocument) - return is_hidden(aElement.parentNode); - - return false; -} - -function is_element_visible(aElement, aMsg) { - isnot(aElement, null, "Element should not be null, when checking visibility"); - ok(!is_hidden(aElement), aMsg || (aElement + " should be visible")); -} - -function is_element_hidden(aElement, aMsg) { - isnot(aElement, null, "Element should not be null, when checking visibility"); - ok(is_hidden(aElement), aMsg || (aElement + " should be hidden")); -} - -function promiseAddonByID(aId) { - return new Promise(resolve => { - AddonManager.getAddonByID(aId, resolve); - }); -} - -function promiseAddonsByIDs(aIDs) { - return new Promise(resolve => { - AddonManager.getAddonsByIDs(aIDs, resolve); - }); -} -/** - * Install an add-on and call a callback when complete. - * - * The callback will receive the Addon for the installed add-on. - */ -function install_addon(path, cb, pathPrefix=TESTROOT) { - let p = new Promise((resolve, reject) => { - AddonManager.getInstallForURL(pathPrefix + path, (install) => { - install.addListener({ - onInstallEnded: () => resolve(install.addon), - }); - - install.install(); - }, "application/x-xpinstall"); - }); - - return log_callback(p, cb); -} - -function CategoryUtilities(aManagerWindow) { - this.window = aManagerWindow; - - var self = this; - this.window.addEventListener("unload", function() { - self.window.removeEventListener("unload", arguments.callee, false); - self.window = null; - }, false); -} - -CategoryUtilities.prototype = { - window: null, - - get selectedCategory() { - isnot(this.window, null, "Should not get selected category when manager window is not loaded"); - var selectedItem = this.window.document.getElementById("categories").selectedItem; - isnot(selectedItem, null, "A category should be selected"); - var view = this.window.gViewController.parseViewId(selectedItem.value); - return (view.type == "list") ? view.param : view.type; - }, - - get: function(aCategoryType, aAllowMissing) { - isnot(this.window, null, "Should not get category when manager window is not loaded"); - var categories = this.window.document.getElementById("categories"); - - var viewId = "addons://list/" + aCategoryType; - var items = categories.getElementsByAttribute("value", viewId); - if (items.length) - return items[0]; - - viewId = "addons://" + aCategoryType + "/"; - items = categories.getElementsByAttribute("value", viewId); - if (items.length) - return items[0]; - - if (!aAllowMissing) - ok(false, "Should have found a category with type " + aCategoryType); - return null; - }, - - getViewId: function(aCategoryType) { - isnot(this.window, null, "Should not get view id when manager window is not loaded"); - return this.get(aCategoryType).value; - }, - - isVisible: function(aCategory) { - isnot(this.window, null, "Should not check visible state when manager window is not loaded"); - if (aCategory.hasAttribute("disabled") && - aCategory.getAttribute("disabled") == "true") - return false; - - return !is_hidden(aCategory); - }, - - isTypeVisible: function(aCategoryType) { - return this.isVisible(this.get(aCategoryType)); - }, - - open: function(aCategory, aCallback) { - - isnot(this.window, null, "Should not open category when manager window is not loaded"); - ok(this.isVisible(aCategory), "Category should be visible if attempting to open it"); - - EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window); - let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve)); - - return log_callback(p, aCallback); - }, - - openType: function(aCategoryType, aCallback) { - return this.open(this.get(aCategoryType), aCallback); - } -} - -function CertOverrideListener(host, bits) { - this.host = host; - this.bits = bits; -} - -CertOverrideListener.prototype = { - host: null, - bits: null, - - getInterface: function (aIID) { - return this.QueryInterface(aIID); - }, - - QueryInterface: function(aIID) { - if (aIID.equals(Ci.nsIBadCertListener2) || - aIID.equals(Ci.nsIInterfaceRequestor) || - aIID.equals(Ci.nsISupports)) - return this; - - throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); - }, - - notifyCertProblem: function (socketInfo, sslStatus, targetHost) { - var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus) - .serverCert; - var cos = Cc["@mozilla.org/security/certoverride;1"]. - getService(Ci.nsICertOverrideService); - cos.rememberValidityOverride(this.host, -1, cert, this.bits, false); - return true; - } -} - -// Add overrides for the bad certificates -function addCertOverride(host, bits) { - var req = new XMLHttpRequest(); - try { - req.open("GET", "https://" + host + "/", false); - req.channel.notificationCallbacks = new CertOverrideListener(host, bits); - req.send(null); - } - catch (e) { - // This request will fail since the SSL server is not trusted yet - } -} - -/** *** Mock Provider *****/ - -function MockProvider(aUseAsyncCallbacks, aTypes) { - this.addons = []; - this.installs = []; - this.callbackTimers = []; - this.timerLocations = new Map(); - this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks; - this.types = (aTypes === undefined) ? [{ - id: "extension", - name: "Extensions", - uiPriority: 4000, - flags: AddonManager.TYPE_UI_VIEW_LIST | - AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL, - }] : aTypes; - - var self = this; - registerCleanupFunction(function() { - if (self.started) - self.unregister(); - }); - - this.register(); -} - -MockProvider.prototype = { - addons: null, - installs: null, - started: null, - apiDelay: 10, - callbackTimers: null, - timerLocations: null, - useAsyncCallbacks: null, - types: null, - - /** *** Utility functions *****/ - - /** - * Register this provider with the AddonManager - */ - register: function MP_register() { - info("Registering mock add-on provider"); - AddonManagerPrivate.registerProvider(this, this.types); - }, - - /** - * Unregister this provider with the AddonManager - */ - unregister: function MP_unregister() { - info("Unregistering mock add-on provider"); - AddonManagerPrivate.unregisterProvider(this); - }, - - /** - * Adds an add-on to the list of add-ons that this provider exposes to the - * AddonManager, dispatching appropriate events in the process. - * - * @param aAddon - * The add-on to add - */ - addAddon: function MP_addAddon(aAddon) { - var oldAddons = this.addons.filter(aOldAddon => aOldAddon.id == aAddon.id); - var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null; - - this.addons = this.addons.filter(aOldAddon => aOldAddon.id != aAddon.id); - - this.addons.push(aAddon); - aAddon._provider = this; - - if (!this.started) - return; - - let requiresRestart = (aAddon.operationsRequiringRestart & - AddonManager.OP_NEEDS_RESTART_INSTALL) != 0; - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon, - oldAddon, requiresRestart) - }, - - /** - * Removes an add-on from the list of add-ons that this provider exposes to - * the AddonManager, dispatching the onUninstalled event in the process. - * - * @param aAddon - * The add-on to add - */ - removeAddon: function MP_removeAddon(aAddon) { - var pos = this.addons.indexOf(aAddon); - if (pos == -1) { - ok(false, "Tried to remove an add-on that wasn't registered with the mock provider"); - return; - } - - this.addons.splice(pos, 1); - - if (!this.started) - return; - - AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon); - }, - - /** - * Adds an add-on install to the list of installs that this provider exposes - * to the AddonManager, dispatching appropriate events in the process. - * - * @param aInstall - * The add-on install to add - */ - addInstall: function MP_addInstall(aInstall) { - this.installs.push(aInstall); - aInstall._provider = this; - - if (!this.started) - return; - - aInstall.callListeners("onNewInstall"); - }, - - removeInstall: function MP_removeInstall(aInstall) { - var pos = this.installs.indexOf(aInstall); - if (pos == -1) { - ok(false, "Tried to remove an install that wasn't registered with the mock provider"); - return; - } - - this.installs.splice(pos, 1); - }, - - /** - * Creates a set of mock add-on objects and adds them to the list of add-ons - * managed by this provider. - * - * @param aAddonProperties - * An array of objects containing properties describing the add-ons - * @return Array of the new MockAddons - */ - createAddons: function MP_createAddons(aAddonProperties) { - var newAddons = []; - for (let addonProp of aAddonProperties) { - let addon = new MockAddon(addonProp.id); - for (let prop in addonProp) { - if (prop == "id") - continue; - if (prop == "applyBackgroundUpdates") { - addon._applyBackgroundUpdates = addonProp[prop]; - continue; - } - if (prop == "appDisabled") { - addon._appDisabled = addonProp[prop]; - continue; - } - addon[prop] = addonProp[prop]; - } - if (!addon.optionsType && !!addon.optionsURL) - addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG; - - // Make sure the active state matches the passed in properties - addon.isActive = addon.shouldBeActive; - - this.addAddon(addon); - newAddons.push(addon); - } - - return newAddons; - }, - - /** - * Creates a set of mock add-on install objects and adds them to the list - * of installs managed by this provider. - * - * @param aInstallProperties - * An array of objects containing properties describing the installs - * @return Array of the new MockInstalls - */ - createInstalls: function MP_createInstalls(aInstallProperties) { - var newInstalls = []; - for (let installProp of aInstallProperties) { - let install = new MockInstall(installProp.name || null, - installProp.type || null, - null); - for (let prop in installProp) { - switch (prop) { - case "name": - case "type": - break; - case "sourceURI": - install[prop] = NetUtil.newURI(installProp[prop]); - break; - default: - install[prop] = installProp[prop]; - } - } - this.addInstall(install); - newInstalls.push(install); - } - - return newInstalls; - }, - - /** *** AddonProvider implementation *****/ - - /** - * Called to initialize the provider. - */ - startup: function MP_startup() { - this.started = true; - }, - - /** - * Called when the provider should shutdown. - */ - shutdown: function MP_shutdown() { - if (this.callbackTimers.length) { - info("MockProvider: pending callbacks at shutdown(): calling immediately"); - } - while (this.callbackTimers.length > 0) { - // When we notify the callback timer, it removes itself from our array - let timer = this.callbackTimers[0]; - try { - let setAt = this.timerLocations.get(timer); - info("Notifying timer set at " + (setAt || "unknown location")); - timer.callback.notify(timer); - timer.cancel(); - } catch (e) { - info("Timer notify failed: " + e); - } - } - this.callbackTimers = []; - this.timerLocations = null; - - this.started = false; - }, - - /** - * Called to get an Addon with a particular ID. - * - * @param aId - * The ID of the add-on to retrieve - * @param aCallback - * A callback to pass the Addon to - */ - getAddonByID: function MP_getAddon(aId, aCallback) { - for (let addon of this.addons) { - if (addon.id == aId) { - this._delayCallback(aCallback, addon); - return; - } - } - - aCallback(null); - }, - - /** - * Called to get Addons of a particular type. - * - * @param aTypes - * An array of types to fetch. Can be null to get all types. - * @param callback - * A callback to pass an array of Addons to - */ - getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) { - var addons = this.addons.filter(function(aAddon) { - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) - return false; - return true; - }); - this._delayCallback(aCallback, addons); - }, - - /** - * Called to get Addons that have pending operations. - * - * @param aTypes - * An array of types to fetch. Can be null to get all types - * @param aCallback - * A callback to pass an array of Addons to - */ - getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) { - var addons = this.addons.filter(function(aAddon) { - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) - return false; - return aAddon.pendingOperations != 0; - }); - this._delayCallback(aCallback, addons); - }, - - /** - * Called to get the current AddonInstalls, optionally restricting by type. - * - * @param aTypes - * An array of types or null to get all types - * @param aCallback - * A callback to pass the array of AddonInstalls to - */ - getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) { - var installs = this.installs.filter(function(aInstall) { - // Appear to have actually removed cancelled installs from the provider - if (aInstall.state == AddonManager.STATE_CANCELLED) - return false; - - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1) - return false; - - return true; - }); - this._delayCallback(aCallback, installs); - }, - - /** - * Called when a new add-on has been enabled when only one add-on of that type - * can be enabled. - * - * @param aId - * The ID of the newly enabled add-on - * @param aType - * The type of the newly enabled add-on - * @param aPendingRestart - * true if the newly enabled add-on will only become enabled after a - * restart - */ - addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { - // Not implemented - }, - - /** - * Update the appDisabled property for all add-ons. - */ - updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() { - // Not needed - }, - - /** - * Called to get an AddonInstall to download and install an add-on from a URL. - * - * @param aUrl - * The URL to be installed - * @param aHash - * A hash for the install - * @param aName - * A name for the install - * @param aIconURL - * An icon URL for the install - * @param aVersion - * A version for the install - * @param aLoadGroup - * An nsILoadGroup to associate requests with - * @param aCallback - * A callback to pass the AddonInstall to - */ - getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL, - aVersion, aLoadGroup, aCallback) { - // Not yet implemented - }, - - /** - * Called to get an AddonInstall to install an add-on from a local file. - * - * @param aFile - * The file to be installed - * @param aCallback - * A callback to pass the AddonInstall to - */ - getInstallForFile: function MP_getInstallForFile(aFile, aCallback) { - // Not yet implemented - }, - - /** - * Called to test whether installing add-ons is enabled. - * - * @return true if installing is enabled - */ - isInstallEnabled: function MP_isInstallEnabled() { - return false; - }, - - /** - * Called to test whether this provider supports installing a particular - * mimetype. - * - * @param aMimetype - * The mimetype to check for - * @return true if the mimetype is supported - */ - supportsMimetype: function MP_supportsMimetype(aMimetype) { - return false; - }, - - /** - * Called to test whether installing add-ons from a URI is allowed. - * - * @param aUri - * The URI being installed from - * @return true if installing is allowed - */ - isInstallAllowed: function MP_isInstallAllowed(aUri) { - return false; - }, - - - /** *** Internal functions *****/ - - /** - * Delay calling a callback to fake a time-consuming async operation. - * The delay is specified by the apiDelay property, in milliseconds. - * Parameters to send to the callback should be specified as arguments after - * the aCallback argument. - * - * @param aCallback Callback to eventually call - */ - _delayCallback: function MP_delayCallback(aCallback, ...aArgs) { - if (!this.useAsyncCallbacks) { - aCallback(...aArgs); - return; - } - - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - // Need to keep a reference to the timer, so it doesn't get GC'ed - this.callbackTimers.push(timer); - // Capture a stack trace where the timer was set - // needs the 'new Error' hack until bug 1007656 - this.timerLocations.set(timer, Log.stackTrace(new Error("dummy"))); - timer.initWithCallback(() => { - let idx = this.callbackTimers.indexOf(timer); - if (idx == -1) { - dump("MockProvider._delayCallback lost track of timer set at " - + (this.timerLocations.get(timer) || "unknown location") + "\n"); - } else { - this.callbackTimers.splice(idx, 1); - } - this.timerLocations.delete(timer); - aCallback(...aArgs); - }, this.apiDelay, timer.TYPE_ONE_SHOT); - } -}; - -/** *** Mock Addon object for the Mock Provider *****/ - -function MockAddon(aId, aName, aType, aOperationsRequiringRestart) { - // Only set required attributes. - this.id = aId || ""; - this.name = aName || ""; - this.type = aType || "extension"; - this.version = ""; - this.isCompatible = true; - this.providesUpdatesSecurely = true; - this.blocklistState = 0; - this._appDisabled = false; - this._userDisabled = false; - this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE; - this.scope = AddonManager.SCOPE_PROFILE; - this.isActive = true; - this.creator = ""; - this.pendingOperations = 0; - this._permissions = AddonManager.PERM_CAN_UNINSTALL | - AddonManager.PERM_CAN_ENABLE | - AddonManager.PERM_CAN_DISABLE | - AddonManager.PERM_CAN_UPGRADE; - this.operationsRequiringRestart = (aOperationsRequiringRestart != undefined) ? - aOperationsRequiringRestart : - (AddonManager.OP_NEEDS_RESTART_INSTALL | - AddonManager.OP_NEEDS_RESTART_UNINSTALL | - AddonManager.OP_NEEDS_RESTART_ENABLE | - AddonManager.OP_NEEDS_RESTART_DISABLE); -} - -MockAddon.prototype = { - get isCorrectlySigned() { - if (this.signedState === AddonManager.SIGNEDSTATE_NOT_REQUIRED) - return true; - return this.signedState > AddonManager.SIGNEDSTATE_MISSING; - }, - - get shouldBeActive() { - return !this.appDisabled && !this._userDisabled && - !(this.pendingOperations & AddonManager.PENDING_UNINSTALL); - }, - - get appDisabled() { - return this._appDisabled; - }, - - set appDisabled(val) { - if (val == this._appDisabled) - return val; - - AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]); - - var currentActive = this.shouldBeActive; - this._appDisabled = val; - var newActive = this.shouldBeActive; - this._updateActiveState(currentActive, newActive); - - return val; - }, - - get userDisabled() { - return this._userDisabled; - }, - - set userDisabled(val) { - if (val == this._userDisabled) - return val; - - var currentActive = this.shouldBeActive; - this._userDisabled = val; - var newActive = this.shouldBeActive; - this._updateActiveState(currentActive, newActive); - - return val; - }, - - get permissions() { - let permissions = this._permissions; - if (this.appDisabled || !this._userDisabled) - permissions &= ~AddonManager.PERM_CAN_ENABLE; - if (this.appDisabled || this._userDisabled) - permissions &= ~AddonManager.PERM_CAN_DISABLE; - return permissions; - }, - - set permissions(val) { - return this._permissions = val; - }, - - get applyBackgroundUpdates() { - return this._applyBackgroundUpdates; - }, - - set applyBackgroundUpdates(val) { - if (val != AddonManager.AUTOUPDATE_DEFAULT && - val != AddonManager.AUTOUPDATE_DISABLE && - val != AddonManager.AUTOUPDATE_ENABLE) { - ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val); - } - this._applyBackgroundUpdates = val; - AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]); - }, - - isCompatibleWith: function(aAppVersion, aPlatformVersion) { - return true; - }, - - findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { - // Tests can implement this if they need to - }, - - uninstall: function(aAlwaysAllowUndo = false) { - if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL) - && this.pendingOperations & AddonManager.PENDING_UNINSTALL) - throw Components.Exception("Add-on is already pending uninstall"); - - var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL); - this.pendingOperations |= AddonManager.PENDING_UNINSTALL; - AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart); - if (!needsRestart) { - this.pendingOperations -= AddonManager.PENDING_UNINSTALL; - this._provider.removeAddon(this); - } else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) { - this.isActive = false; - } - }, - - cancelUninstall: function() { - if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL)) - throw Components.Exception("Add-on is not pending uninstall"); - - this.pendingOperations -= AddonManager.PENDING_UNINSTALL; - this.isActive = this.shouldBeActive; - AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); - }, - - markAsSeen: function() { - this.seen = true; - }, - - _updateActiveState: function(currentActive, newActive) { - if (currentActive == newActive) - return; - - if (newActive == this.isActive) { - this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE); - AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); - } - else if (newActive) { - let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE); - this.pendingOperations |= AddonManager.PENDING_ENABLE; - AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart); - if (!needsRestart) { - this.isActive = newActive; - this.pendingOperations -= AddonManager.PENDING_ENABLE; - AddonManagerPrivate.callAddonListeners("onEnabled", this); - } - } - else { - let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE); - this.pendingOperations |= AddonManager.PENDING_DISABLE; - AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart); - if (!needsRestart) { - this.isActive = newActive; - this.pendingOperations -= AddonManager.PENDING_DISABLE; - AddonManagerPrivate.callAddonListeners("onDisabled", this); - } - } - } -}; - -/** *** Mock AddonInstall object for the Mock Provider *****/ - -function MockInstall(aName, aType, aAddonToInstall) { - this.name = aName || ""; - // Don't expose type until download completed - this._type = aType || "extension"; - this.type = null; - this.version = "1.0"; - this.iconURL = ""; - this.infoURL = ""; - this.state = AddonManager.STATE_AVAILABLE; - this.error = 0; - this.sourceURI = null; - this.file = null; - this.progress = 0; - this.maxProgress = -1; - this.certificate = null; - this.certName = ""; - this.existingAddon = null; - this.addon = null; - this._addonToInstall = aAddonToInstall; - this.listeners = []; - - // Another type of install listener for tests that want to check the results - // of code run from standard install listeners - this.testListeners = []; -} - -MockInstall.prototype = { - install: function() { - switch (this.state) { - case AddonManager.STATE_AVAILABLE: - this.state = AddonManager.STATE_DOWNLOADING; - if (!this.callListeners("onDownloadStarted")) { - this.state = AddonManager.STATE_CANCELLED; - this.callListeners("onDownloadCancelled"); - return; - } - - this.type = this._type; - - // Adding addon to MockProvider to be implemented when needed - if (this._addonToInstall) - this.addon = this._addonToInstall; - else { - this.addon = new MockAddon("", this.name, this.type); - this.addon.version = this.version; - this.addon.pendingOperations = AddonManager.PENDING_INSTALL; - } - this.addon.install = this; - if (this.existingAddon) { - if (!this.addon.id) - this.addon.id = this.existingAddon.id; - this.existingAddon.pendingUpgrade = this.addon; - this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE; - } - - this.state = AddonManager.STATE_DOWNLOADED; - this.callListeners("onDownloadEnded"); - - case AddonManager.STATE_DOWNLOADED: - this.state = AddonManager.STATE_INSTALLING; - if (!this.callListeners("onInstallStarted")) { - this.state = AddonManager.STATE_CANCELLED; - this.callListeners("onInstallCancelled"); - return; - } - - let needsRestart = (this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_INSTALL); - AddonManagerPrivate.callAddonListeners("onInstalling", this.addon, needsRestart); - if (!needsRestart) { - AddonManagerPrivate.callAddonListeners("onInstalled", this.addon); - } - - this.state = AddonManager.STATE_INSTALLED; - this.callListeners("onInstallEnded"); - break; - case AddonManager.STATE_DOWNLOADING: - case AddonManager.STATE_CHECKING: - case AddonManager.STATE_INSTALLING: - // Installation is already running - return; - default: - ok(false, "Cannot start installing when state = " + this.state); - } - }, - - cancel: function() { - switch (this.state) { - case AddonManager.STATE_AVAILABLE: - this.state = AddonManager.STATE_CANCELLED; - break; - case AddonManager.STATE_INSTALLED: - this.state = AddonManager.STATE_CANCELLED; - this._provider.removeInstall(this); - this.callListeners("onInstallCancelled"); - break; - default: - // Handling cancelling when downloading to be implemented when needed - ok(false, "Cannot cancel when state = " + this.state); - } - }, - - - addListener: function(aListener) { - if (!this.listeners.some(i => i == aListener)) - this.listeners.push(aListener); - }, - - removeListener: function(aListener) { - this.listeners = this.listeners.filter(i => i != aListener); - }, - - addTestListener: function(aListener) { - if (!this.testListeners.some(i => i == aListener)) - this.testListeners.push(aListener); - }, - - removeTestListener: function(aListener) { - this.testListeners = this.testListeners.filter(i => i != aListener); - }, - - callListeners: function(aMethod) { - var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners, - this, this.addon); - - // Call test listeners after standard listeners to remove race condition - // between standard and test listeners - for (let listener of this.testListeners) { - try { - if (aMethod in listener) - if (listener[aMethod].call(listener, this, this.addon) === false) - result = false; - } - catch (e) { - ok(false, "Test listener threw exception: " + e); - } - } - - return result; - } -}; - -function waitForCondition(condition, nextTest, errorMsg) { - let tries = 0; - let interval = setInterval(function() { - if (tries >= 30) { - ok(false, errorMsg); - moveOn(); - } - var conditionPassed; - try { - conditionPassed = condition(); - } catch (e) { - ok(false, e + "\n" + e.stack); - conditionPassed = false; - } - if (conditionPassed) { - moveOn(); - } - tries++; - }, 100); - let moveOn = function() { clearInterval(interval); nextTest(); }; -} - -function getTestPluginTag() { - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let tags = ph.getPluginTags(); - - // Find the test plugin - for (let i = 0; i < tags.length; i++) { - if (tags[i].name == "Test Plug-in") - return tags[i]; - } - ok(false, "Unable to find plugin"); - return null; -} diff --git a/toolkit/mozapps/extensions/test/browser/more_options.xul b/toolkit/mozapps/extensions/test/browser/more_options.xul deleted file mode 100644 index 28dbb0a2e..000000000 --- a/toolkit/mozapps/extensions/test/browser/more_options.xul +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/toolkit/mozapps/extensions/test/browser/moz.build b/toolkit/mozapps/extensions/test/browser/moz.build deleted file mode 100644 index af04aaeef..000000000 --- a/toolkit/mozapps/extensions/test/browser/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -BROWSER_CHROME_MANIFESTS += [ - 'browser-window.ini', - 'browser.ini', -] diff --git a/toolkit/mozapps/extensions/test/browser/options.xul b/toolkit/mozapps/extensions/test/browser/options.xul deleted file mode 100644 index 1b6827915..000000000 --- a/toolkit/mozapps/extensions/test/browser/options.xul +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Description Text Node - - This is a test, -

-

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs deleted file mode 100644 index 92bccd9ec..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs +++ /dev/null @@ -1,24 +0,0 @@ -// Simple script redirects to the query part of the uri if the cookie "xpinstall" -// has the value "true", otherwise gives a 500 error. - -function handleRequest(request, response) -{ - let cookie = null; - if (request.hasHeader("Cookie")) { - let cookies = request.getHeader("Cookie").split(";"); - for (let i = 0; i < cookies.length; i++) { - if (cookies[i].substring(0, 10) == "xpinstall=") - cookie = cookies[i].substring(10); - } - } - - if (cookie == "true") { - response.setStatusLine(request.httpVersion, 302, "Found"); - response.setHeader("Location", request.queryString); - response.write("See " + request.queryString); - } - else { - response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); - response.write("Invalid request"); - } -} diff --git a/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi b/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi deleted file mode 100644 index 35d7bd5e5..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi +++ /dev/null @@ -1 +0,0 @@ -This is a corrupt zip file diff --git a/toolkit/mozapps/extensions/test/xpinstall/empty.xpi b/toolkit/mozapps/extensions/test/xpinstall/empty.xpi deleted file mode 100644 index 74ed2b817..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/empty.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/enabled.html b/toolkit/mozapps/extensions/test/xpinstall/enabled.html deleted file mode 100644 index 370cde8fb..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/enabled.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - -InstallTrigger tests - - - -

InstallTrigger tests

-

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs deleted file mode 100644 index 324a092a3..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs +++ /dev/null @@ -1,15 +0,0 @@ -// Simple script redirects takes the query part of te request and splits it on -// the | character. Anything before is included as the X-Target-Digest header -// the latter part is used as the url to redirect to - -function handleRequest(request, response) -{ - let pos = request.queryString.indexOf("|"); - let header = request.queryString.substring(0, pos); - let url = request.queryString.substring(pos + 1); - - response.setStatusLine(request.httpVersion, 302, "Found"); - response.setHeader("X-Target-Digest", header); - response.setHeader("Location", url); - response.write("See " + url); -} diff --git a/toolkit/mozapps/extensions/test/xpinstall/head.js b/toolkit/mozapps/extensions/test/xpinstall/head.js deleted file mode 100644 index 197fe3fac..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/head.js +++ /dev/null @@ -1,434 +0,0 @@ -const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/"; - -const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; -const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR; -const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; -const PROMPT_URL = "chrome://global/content/commonDialog.xul"; -const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul"; -const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; -const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts"; -const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin"; -const PREF_CUSTOM_CONFIRMATION_UI = "xpinstall.customConfirmationUI"; -const CHROME_NAME = "mochikit"; - -function getChromeRoot(path) { - if (path === undefined) { - return "chrome://" + CHROME_NAME + "/content/browser/" + RELATIVE_DIR - } - return getRootDirectory(path); -} - -function extractChromeRoot(path) { - var chromeRootPath = getChromeRoot(path); - var jar = getJar(chromeRootPath); - if (jar) { - var tmpdir = extractJarToTmp(jar); - return "file://" + tmpdir.path + "/"; - } - return chromeRootPath; -} - -Services.prefs.setBoolPref(PREF_CUSTOM_CONFIRMATION_UI, false); -registerCleanupFunction(() => { - Services.prefs.clearUserPref(PREF_CUSTOM_CONFIRMATION_UI); -}); - -/** - * This is a test harness designed to handle responding to UI during the process - * of installing an XPI. A test can set callbacks to hear about specific parts - * of the sequence. - * Before use setup must be called and finish must be called afterwards. - */ -var Harness = { - // If set then the callback is called when an install is attempted and - // software installation is disabled. - installDisabledCallback: null, - // If set then the callback is called when an install is attempted and - // then canceled. - installCancelledCallback: null, - // If set then the callback will be called when an install's origin is blocked. - installOriginBlockedCallback: null, - // If set then the callback will be called when an install is blocked by the - // whitelist. The callback should return true to continue with the install - // anyway. - installBlockedCallback: null, - // If set will be called in the event of authentication being needed to get - // the xpi. Should return a 2 element array of username and password, or - // null to not authenticate. - authenticationCallback: null, - // If set this will be called to allow checking the contents of the xpinstall - // confirmation dialog. The callback should return true to continue the install. - installConfirmCallback: null, - // If set will be called when downloading of an item has begun. - downloadStartedCallback: null, - // If set will be called during the download of an item. - downloadProgressCallback: null, - // If set will be called when an xpi fails to download. - downloadFailedCallback: null, - // If set will be called when an xpi download is cancelled. - downloadCancelledCallback: null, - // If set will be called when downloading of an item has ended. - downloadEndedCallback: null, - // If set will be called when installation by the extension manager of an xpi - // item starts - installStartedCallback: null, - // If set will be called when an xpi fails to install. - installFailedCallback: null, - // If set will be called when each xpi item to be installed completes - // installation. - installEndedCallback: null, - // If set will be called when all triggered items are installed or the install - // is canceled. - installsCompletedCallback: null, - // If set the harness will wait for this DOM event before calling - // installsCompletedCallback - finalContentEvent: null, - - waitingForEvent: false, - pendingCount: null, - installCount: null, - runningInstalls: null, - - waitingForFinish: false, - - // A unique value to return from the installConfirmCallback to indicate that - // the install UI shouldn't be closed automatically - leaveOpen: {}, - - // Setup and tear down functions - setup: function() { - if (!this.waitingForFinish) { - waitForExplicitFinish(); - this.waitingForFinish = true; - - Services.prefs.setBoolPref(PREF_INSTALL_REQUIRESECUREORIGIN, false); - - Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); - Services.obs.addObserver(this, "addon-install-started", false); - Services.obs.addObserver(this, "addon-install-disabled", false); - Services.obs.addObserver(this, "addon-install-origin-blocked", false); - Services.obs.addObserver(this, "addon-install-blocked", false); - Services.obs.addObserver(this, "addon-install-failed", false); - Services.obs.addObserver(this, "addon-install-complete", false); - - AddonManager.addInstallListener(this); - - Services.wm.addListener(this); - - var self = this; - registerCleanupFunction(function() { - Services.prefs.clearUserPref(PREF_LOGGING_ENABLED); - Services.prefs.clearUserPref(PREF_INSTALL_REQUIRESECUREORIGIN); - Services.obs.removeObserver(self, "addon-install-started"); - Services.obs.removeObserver(self, "addon-install-disabled"); - Services.obs.removeObserver(self, "addon-install-origin-blocked"); - Services.obs.removeObserver(self, "addon-install-blocked"); - Services.obs.removeObserver(self, "addon-install-failed"); - Services.obs.removeObserver(self, "addon-install-complete"); - - AddonManager.removeInstallListener(self); - - Services.wm.removeListener(self); - - AddonManager.getAllInstalls(function(aInstalls) { - is(aInstalls.length, 0, "Should be no active installs at the end of the test"); - aInstalls.forEach(function(aInstall) { - info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); - aInstall.cancel(); - }); - }); - }); - } - - this.installCount = 0; - this.pendingCount = 0; - this.runningInstalls = []; - }, - - finish: function() { - finish(); - }, - - endTest: function() { - let callback = this.installsCompletedCallback; - let count = this.installCount; - - is(this.runningInstalls.length, 0, "Should be no running installs left"); - this.runningInstalls.forEach(function(aInstall) { - info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); - }); - - this.installOriginBlockedCallback = null; - this.installBlockedCallback = null; - this.authenticationCallback = null; - this.installConfirmCallback = null; - this.downloadStartedCallback = null; - this.downloadProgressCallback = null; - this.downloadCancelledCallback = null; - this.downloadFailedCallback = null; - this.downloadEndedCallback = null; - this.installStartedCallback = null; - this.installFailedCallback = null; - this.installEndedCallback = null; - this.installsCompletedCallback = null; - this.runningInstalls = null; - - if (callback) - executeSoon(() => callback(count)); - }, - - // Window open handling - windowReady: function(window) { - if (window.document.location.href == XPINSTALL_URL) { - if (this.installBlockedCallback) - ok(false, "Should have been blocked by the whitelist"); - this.pendingCount = window.document.getElementById("itemList").childNodes.length; - - // If there is a confirm callback then its return status determines whether - // to install the items or not. If not the test is over. - let result = true; - if (this.installConfirmCallback) { - result = this.installConfirmCallback(window); - if (result === this.leaveOpen) - return; - } - - if (!result) { - window.document.documentElement.cancelDialog(); - } - else { - // Initially the accept button is disabled on a countdown timer - var button = window.document.documentElement.getButton("accept"); - button.disabled = false; - window.document.documentElement.acceptDialog(); - } - } - else if (window.document.location.href == PROMPT_URL) { - var promptType = window.args.promptType; - switch (promptType) { - case "alert": - case "alertCheck": - case "confirmCheck": - case "confirm": - case "confirmEx": - window.document.documentElement.acceptDialog(); - break; - case "promptUserAndPass": - // This is a login dialog, hopefully an authentication prompt - // for the xpi. - if (this.authenticationCallback) { - var auth = this.authenticationCallback(); - if (auth && auth.length == 2) { - window.document.getElementById("loginTextbox").value = auth[0]; - window.document.getElementById("password1Textbox").value = auth[1]; - window.document.documentElement.acceptDialog(); - } - else { - window.document.documentElement.cancelDialog(); - } - } - else { - window.document.documentElement.cancelDialog(); - } - break; - default: - ok(false, "prompt type " + promptType + " not handled in test."); - break; - } - } - }, - - // Install blocked handling - - installDisabled: function(installInfo) { - ok(!!this.installDisabledCallback, "Installation shouldn't have been disabled"); - if (this.installDisabledCallback) - this.installDisabledCallback(installInfo); - this.expectingCancelled = true; - this.expectingCancelled = false; - this.endTest(); - }, - - installCancelled: function(installInfo) { - if (this.expectingCancelled) - return; - - ok(!!this.installCancelledCallback, "Installation shouldn't have been cancelled"); - if (this.installCancelledCallback) - this.installCancelledCallback(installInfo); - this.endTest(); - }, - - installOriginBlocked: function(installInfo) { - ok(!!this.installOriginBlockedCallback, "Shouldn't have been blocked"); - if (this.installOriginBlockedCallback) - this.installOriginBlockedCallback(installInfo); - this.endTest(); - }, - - installBlocked: function(installInfo) { - ok(!!this.installBlockedCallback, "Shouldn't have been blocked by the whitelist"); - if (this.installBlockedCallback && this.installBlockedCallback(installInfo)) { - this.installBlockedCallback = null; - installInfo.install(); - } - else { - this.expectingCancelled = true; - installInfo.installs.forEach(function(install) { - install.cancel(); - }); - this.expectingCancelled = false; - this.endTest(); - } - }, - - // nsIWindowMediatorListener - - onWindowTitleChange: function(window, title) { - }, - - onOpenWindow: function(window) { - var domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindow); - var self = this; - waitForFocus(function() { - self.windowReady(domwindow); - }, domwindow); - }, - - onCloseWindow: function(window) { - }, - - // Addon Install Listener - - onNewInstall: function(install) { - this.runningInstalls.push(install); - - if (this.finalContentEvent && !this.waitingForEvent) { - this.waitingForEvent = true; - info("Waiting for " + this.finalContentEvent); - let mm = gBrowser.selectedBrowser.messageManager; - mm.loadFrameScript(`data:,content.addEventListener("${this.finalContentEvent}", () => { sendAsyncMessage("Test:GotNewInstallEvent"); });`, false); - let win = gBrowser.contentWindow; - let listener = () => { - info("Saw " + this.finalContentEvent); - mm.removeMessageListener("Test:GotNewInstallEvent", listener); - this.waitingForEvent = false; - if (this.pendingCount == 0) - this.endTest(); - } - mm.addMessageListener("Test:GotNewInstallEvent", listener); - } - }, - - onDownloadStarted: function(install) { - this.pendingCount++; - if (this.downloadStartedCallback) - this.downloadStartedCallback(install); - }, - - onDownloadProgress: function(install) { - if (this.downloadProgressCallback) - this.downloadProgressCallback(install); - }, - - onDownloadEnded: function(install) { - if (this.downloadEndedCallback) - this.downloadEndedCallback(install); - }, - - onDownloadCancelled: function(install) { - isnot(this.runningInstalls.indexOf(install), -1, - "Should only see cancelations for started installs"); - this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1); - - if (this.downloadCancelledCallback) - this.downloadCancelledCallback(install); - this.checkTestEnded(); - }, - - onDownloadFailed: function(install) { - if (this.downloadFailedCallback) - this.downloadFailedCallback(install); - this.checkTestEnded(); - }, - - onInstallStarted: function(install) { - if (this.installStartedCallback) - this.installStartedCallback(install); - }, - - onInstallEnded: function(install, addon) { - if (this.installEndedCallback) - this.installEndedCallback(install, addon); - this.installCount++; - this.checkTestEnded(); - }, - - onInstallFailed: function(install) { - if (this.installFailedCallback) - this.installFailedCallback(install); - this.checkTestEnded(); - }, - - checkTestEnded: function() { - if (--this.pendingCount == 0 && !this.waitingForEvent) - this.endTest(); - }, - - // nsIObserver - - observe: function(subject, topic, data) { - var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo); - switch (topic) { - case "addon-install-started": - is(this.runningInstalls.length, installInfo.installs.length, - "Should have seen the expected number of installs started"); - break; - case "addon-install-disabled": - this.installDisabled(installInfo); - break; - case "addon-install-cancelled": - this.installCancelled(installInfo); - break; - case "addon-install-origin-blocked": - this.installOriginBlocked(installInfo); - break; - case "addon-install-blocked": - this.installBlocked(installInfo); - break; - case "addon-install-failed": - installInfo.installs.forEach(function(aInstall) { - isnot(this.runningInstalls.indexOf(aInstall), -1, - "Should only see failures for started installs"); - - ok(aInstall.error != 0 || aInstall.addon.appDisabled, - "Failed installs should have an error or be appDisabled"); - - this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); - }, this); - break; - case "addon-install-complete": - installInfo.installs.forEach(function(aInstall) { - isnot(this.runningInstalls.indexOf(aInstall), -1, - "Should only see completed events for started installs"); - - is(aInstall.error, 0, "Completed installs should have no error"); - ok(!aInstall.appDisabled, "Completed installs should not be appDisabled"); - - // Complete installs are either in the INSTALLED or CANCELLED state - // since the test may cancel installs the moment they complete. - ok(aInstall.state == AddonManager.STATE_INSTALLED || - aInstall.state == AddonManager.STATE_CANCELLED, - "Completed installs should be in the right state"); - - this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); - }, this); - break; - } - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, - Ci.nsIWindowMediatorListener, - Ci.nsISupports]) -} diff --git a/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi b/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi deleted file mode 100644 index 262ed38a7..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/installchrome.html b/toolkit/mozapps/extensions/test/xpinstall/installchrome.html deleted file mode 100644 index 6abee2ef3..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/installchrome.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -InstallTrigger tests - - - -

InstallTrigger tests

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html b/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html deleted file mode 100644 index 65cab1ef1..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - -InstallTrigger tests - - - -

InstallTrigger tests

-

-

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html b/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html deleted file mode 100644 index 2b302642e..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - -InstallTrigger frame tests - - - - - - -

InstallTrigger tests

-

-

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi b/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi deleted file mode 100644 index d52f28c28..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/navigate.html b/toolkit/mozapps/extensions/test/xpinstall/navigate.html deleted file mode 100644 index 5a6903eb9..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/navigate.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - -Navigation tests - - - - -

Test Link

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs deleted file mode 100644 index d248bfbc7..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs +++ /dev/null @@ -1,45 +0,0 @@ -// Script has two modes based on the query string. If the mode is "setup" then -// parameters from the query string configure the redirection. If the mode is -// "redirect" then a redirect is returned - -function handleRequest(request, response) -{ - let parts = request.queryString.split("&"); - let settings = {}; - - parts.forEach(function(aString) { - let [k, v] = aString.split("="); - settings[k] = decodeURIComponent(v); - }) - - if (settings.mode == "setup") { - delete settings.mode; - - // Object states must be an nsISupports - var state = { - settings: settings, - QueryInterface: function(aIid) { - if (aIid.equals(Components.interfaces.nsISupports)) - return settings; - throw Components.results.NS_ERROR_NO_INTERFACE; - } - } - state.wrappedJSObject = state; - - setObjectState("xpinstall-redirect-settings", state); - response.setStatusLine(request.httpVersion, 200, "Ok"); - response.setHeader("Content-Type", "text/plain"); - response.write("Setup complete"); - } - else if (settings.mode == "redirect") { - getObjectState("xpinstall-redirect-settings", function(aObject) { - settings = aObject.wrappedJSObject.settings; - }); - - response.setStatusLine(request.httpVersion, 302, "Found"); - for (var name in settings) { - response.setHeader(name, settings[name]); - } - response.write("Done"); - } -} diff --git a/toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi b/toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi deleted file mode 100644 index 8e76bd052..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi b/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi deleted file mode 100644 index 9fee8f60b..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-multipackage.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-multipackage.xpi deleted file mode 100644 index 11fbe1861..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed-multipackage.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi deleted file mode 100644 index 90d3a3ce6..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi deleted file mode 100644 index 19b754038..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi deleted file mode 100644 index 8c951881e..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi deleted file mode 100644 index 09789d189..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed.xpi deleted file mode 100644 index bd7f78b7c..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi deleted file mode 100644 index 085efbbf7..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs b/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs deleted file mode 100644 index 5f767a8f4..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs +++ /dev/null @@ -1,101 +0,0 @@ -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/osfile.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); - -const RELATIVE_PATH = "browser/toolkit/mozapps/extensions/test/xpinstall" -const NOTIFICATION_TOPIC = "slowinstall-complete"; - -/** - * Helper function to create a JS object representing the url parameters from - * the request's queryString. - * - * @param aQueryString - * The request's query string. - * @return A JS object representing the url parameters from the request's - * queryString. - */ -function parseQueryString(aQueryString) { - var paramArray = aQueryString.split("&"); - var regex = /^([^=]+)=(.*)$/; - var params = {}; - for (var i = 0, sz = paramArray.length; i < sz; i++) { - var match = regex.exec(paramArray[i]); - if (!match) - throw "Bad parameter in queryString! '" + paramArray[i] + "'"; - params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); - } - - return params; -} - -function handleRequest(aRequest, aResponse) { - let id = +getState("ID"); - setState("ID", "" + (id + 1)); - - function LOG(str) { - dump("slowinstall.sjs[" + id + "]: " + str + "\n"); - } - - aResponse.setStatusLine(aRequest.httpVersion, 200, "OK"); - - var params = { }; - if (aRequest.queryString) - params = parseQueryString(aRequest.queryString); - - if (params.file) { - let xpiFile = ""; - - function complete_download() { - LOG("Completing download"); - downloadPaused = false; - - try { - // Doesn't seem to be a sane way to read using OS.File and write to an - // nsIOutputStream so here we are. - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(xpiFile); - let stream = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - stream.init(file, -1, -1, stream.DEFER_OPEN + stream.CLOSE_ON_EOF); - - NetUtil.asyncCopy(stream, aResponse.bodyOutputStream, () => { - LOG("Download complete"); - aResponse.finish(); - }); - } - catch (e) { - LOG("Exception " + e); - } - } - - let waitForComplete = new Promise(resolve => { - function complete() { - Services.obs.removeObserver(complete, NOTIFICATION_TOPIC); - resolve(); - } - - Services.obs.addObserver(complete, NOTIFICATION_TOPIC, false); - }); - - aResponse.processAsync(); - - OS.File.getCurrentDirectory().then(dir => { - xpiFile = OS.Path.join(dir, ...RELATIVE_PATH.split("/"), params.file); - LOG("Starting slow download of " + xpiFile); - - OS.File.stat(xpiFile).then(info => { - aResponse.setHeader("Content-Type", "binary/octet-stream"); - aResponse.setHeader("Content-Length", info.size.toString()); - - LOG("Download paused"); - waitForComplete.then(complete_download); - }); - }); - } - else if (params.continue) { - dump("slowinstall.sjs: Received signal to complete all current downloads.\n"); - Services.obs.notifyObservers(null, NOTIFICATION_TOPIC, null); - } -} diff --git a/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html b/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html deleted file mode 100644 index 50083ca90..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - -InstallTrigger tests - - - -

InstallTrigger tests

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/theme.xpi b/toolkit/mozapps/extensions/test/xpinstall/theme.xpi deleted file mode 100644 index 74e650b4a..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/theme.xpi and /dev/null differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html deleted file mode 100644 index 42e0e1cd0..000000000 --- a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - -InstallTrigger tests - - - -

InstallTrigger tests

-

-

- - diff --git a/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi b/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi deleted file mode 100644 index 51b00475a..000000000 Binary files a/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi and /dev/null differ diff --git a/toolkit/mozapps/webextensions/.eslintrc.js b/toolkit/mozapps/webextensions/.eslintrc.js new file mode 100644 index 000000000..2b90bd053 --- /dev/null +++ b/toolkit/mozapps/webextensions/.eslintrc.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = { // eslint-disable-line no-undef + "rules": { + // No using undeclared variables + "no-undef": "error", + } +}; diff --git a/toolkit/mozapps/webextensions/AddonContentPolicy.cpp b/toolkit/mozapps/webextensions/AddonContentPolicy.cpp new file mode 100644 index 000000000..90e53b2ea --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonContentPolicy.cpp @@ -0,0 +1,478 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AddonContentPolicy.h" + +#include "mozilla/dom/nsCSPUtils.h" +#include "nsCOMPtr.h" +#include "nsContentPolicyUtils.h" +#include "nsContentTypeParser.h" +#include "nsContentUtils.h" +#include "nsIConsoleService.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIContent.h" +#include "nsIDocument.h" +#include "nsIEffectiveTLDService.h" +#include "nsIScriptError.h" +#include "nsIStringBundle.h" +#include "nsIUUIDGenerator.h" +#include "nsIURI.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" + +using namespace mozilla; + +/* Enforces content policies for WebExtension scopes. Currently: + * + * - Prevents loading scripts with a non-default JavaScript version. + * - Checks custom content security policies for sufficiently stringent + * script-src and object-src directives. + */ + +#define VERSIONED_JS_BLOCKED_MESSAGE \ + u"Versioned JavaScript is a non-standard, deprecated extension, and is " \ + u"not supported in WebExtension code. For alternatives, please see: " \ + u"https://developer.mozilla.org/Add-ons/WebExtensions/Tips" + +AddonContentPolicy::AddonContentPolicy() +{ +} + +AddonContentPolicy::~AddonContentPolicy() +{ +} + +NS_IMPL_ISUPPORTS(AddonContentPolicy, nsIContentPolicy, nsIAddonContentPolicy) + +static nsresult +GetWindowIDFromContext(nsISupports* aContext, uint64_t *aResult) +{ + NS_ENSURE_TRUE(aContext, NS_ERROR_FAILURE); + + nsCOMPtr content = do_QueryInterface(aContext); + NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); + + nsCOMPtr document = content->OwnerDoc(); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + nsCOMPtr window = document->GetInnerWindow(); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + *aResult = window->WindowID(); + return NS_OK; +} + +static nsresult +LogMessage(const nsAString &aMessage, nsIURI* aSourceURI, const nsAString &aSourceSample, + nsISupports* aContext) +{ + nsCOMPtr error = do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + NS_ENSURE_TRUE(error, NS_ERROR_OUT_OF_MEMORY); + + nsCString sourceName = aSourceURI->GetSpecOrDefault(); + + uint64_t windowID = 0; + GetWindowIDFromContext(aContext, &windowID); + + nsresult rv = + error->InitWithWindowID(aMessage, NS_ConvertUTF8toUTF16(sourceName), + aSourceSample, 0, 0, nsIScriptError::errorFlag, + "JavaScript", windowID); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr console = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + NS_ENSURE_TRUE(console, NS_ERROR_OUT_OF_MEMORY); + + console->LogMessage(error); + return NS_OK; +} + + +// Content policy enforcement: + +NS_IMETHODIMP +AddonContentPolicy::ShouldLoad(uint32_t aContentType, + nsIURI* aContentLocation, + nsIURI* aRequestOrigin, + nsISupports* aContext, + const nsACString& aMimeTypeGuess, + nsISupports* aExtra, + nsIPrincipal* aRequestPrincipal, + int16_t* aShouldLoad) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + *aShouldLoad = nsIContentPolicy::ACCEPT; + + if (!aRequestOrigin) { + return NS_OK; + } + + // Only apply this policy to requests from documents loaded from + // moz-extension URLs, or to resources being loaded from moz-extension URLs. + bool equals; + if (!((NS_SUCCEEDED(aContentLocation->SchemeIs("moz-extension", &equals)) && equals) || + (NS_SUCCEEDED(aRequestOrigin->SchemeIs("moz-extension", &equals)) && equals))) { + return NS_OK; + } + + if (aContentType == nsIContentPolicy::TYPE_SCRIPT) { + NS_ConvertUTF8toUTF16 typeString(aMimeTypeGuess); + nsContentTypeParser mimeParser(typeString); + + // Reject attempts to load JavaScript scripts with a non-default version. + nsAutoString mimeType, version; + if (NS_SUCCEEDED(mimeParser.GetType(mimeType)) && + nsContentUtils::IsJavascriptMIMEType(mimeType) && + NS_SUCCEEDED(mimeParser.GetParameter("version", version))) { + *aShouldLoad = nsIContentPolicy::REJECT_REQUEST; + + LogMessage(NS_MULTILINE_LITERAL_STRING(VERSIONED_JS_BLOCKED_MESSAGE), + aRequestOrigin, typeString, aContext); + return NS_OK; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +AddonContentPolicy::ShouldProcess(uint32_t aContentType, + nsIURI* aContentLocation, + nsIURI* aRequestOrigin, + nsISupports* aRequestingContext, + const nsACString& aMimeTypeGuess, + nsISupports* aExtra, + nsIPrincipal* aRequestPrincipal, + int16_t* aShouldProcess) +{ + MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType), + "We should only see external content policy types here."); + + *aShouldProcess = nsIContentPolicy::ACCEPT; + return NS_OK; +} + + +// CSP Validation: + +static const char* allowedSchemes[] = { + "blob", + "filesystem", + nullptr +}; + +static const char* allowedHostSchemes[] = { + "https", + "moz-extension", + nullptr +}; + +/** + * Validates a CSP directive to ensure that it is sufficiently stringent. + * In particular, ensures that: + * + * - No remote sources are allowed other than from https: schemes + * + * - No remote sources specify host wildcards for generic domains + * (*.blogspot.com, *.com, *) + * + * - All remote sources and local extension sources specify a host + * + * - No scheme sources are allowed other than blob:, filesystem:, + * moz-extension:, and https: + * + * - No keyword sources are allowed other than 'none', 'self', 'unsafe-eval', + * and hash sources. + */ +class CSPValidator final : public nsCSPSrcVisitor { + public: + CSPValidator(nsAString& aURL, CSPDirective aDirective, bool aDirectiveRequired = true) : + mURL(aURL), + mDirective(CSP_CSPDirectiveToString(aDirective)), + mFoundSelf(false) + { + // Start with the default error message for a missing directive, since no + // visitors will be called if the directive isn't present. + if (aDirectiveRequired) { + FormatError("csp.error.missing-directive"); + } + } + + // Visitors + + bool visitSchemeSrc(const nsCSPSchemeSrc& src) override + { + nsAutoString scheme; + src.getScheme(scheme); + + if (SchemeInList(scheme, allowedHostSchemes)) { + FormatError("csp.error.missing-host", scheme); + return false; + } + if (!SchemeInList(scheme, allowedSchemes)) { + FormatError("csp.error.illegal-protocol", scheme); + return false; + } + return true; + }; + + bool visitHostSrc(const nsCSPHostSrc& src) override + { + nsAutoString scheme, host; + + src.getScheme(scheme); + src.getHost(host); + + if (scheme.LowerCaseEqualsLiteral("https")) { + if (!HostIsAllowed(host)) { + FormatError("csp.error.illegal-host-wildcard", scheme); + return false; + } + } else if (scheme.LowerCaseEqualsLiteral("moz-extension")) { + // The CSP parser silently converts 'self' keywords to the origin + // URL, so we need to reconstruct the URL to see if it was present. + if (!mFoundSelf) { + nsAutoString url(u"moz-extension://"); + url.Append(host); + + mFoundSelf = url.Equals(mURL); + } + + if (host.IsEmpty() || host.EqualsLiteral("*")) { + FormatError("csp.error.missing-host", scheme); + return false; + } + } else if (!SchemeInList(scheme, allowedSchemes)) { + FormatError("csp.error.illegal-protocol", scheme); + return false; + } + + return true; + }; + + bool visitKeywordSrc(const nsCSPKeywordSrc& src) override + { + switch (src.getKeyword()) { + case CSP_NONE: + case CSP_SELF: + case CSP_UNSAFE_EVAL: + return true; + + default: + NS_ConvertASCIItoUTF16 keyword(CSP_EnumToKeyword(src.getKeyword())); + + FormatError("csp.error.illegal-keyword", keyword); + return false; + } + }; + + bool visitNonceSrc(const nsCSPNonceSrc& src) override + { + FormatError("csp.error.illegal-keyword", NS_LITERAL_STRING("'nonce-*'")); + return false; + }; + + bool visitHashSrc(const nsCSPHashSrc& src) override + { + return true; + }; + + // Accessors + + inline nsAString& GetError() + { + return mError; + }; + + inline bool FoundSelf() + { + return mFoundSelf; + }; + + + // Formatters + + template + inline void FormatError(const char* aName, const T ...aParams) + { + const char16_t* params[] = { mDirective.get(), aParams.get()... }; + FormatErrorParams(aName, params, MOZ_ARRAY_LENGTH(params)); + }; + + private: + // Validators + + bool HostIsAllowed(nsAString& host) + { + if (host.First() == '*') { + if (host.EqualsLiteral("*") || host[1] != '.') { + return false; + } + + host.Cut(0, 2); + + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + + if (!tldService) { + return false; + } + + NS_ConvertUTF16toUTF8 cHost(host); + nsAutoCString publicSuffix; + + nsresult rv = tldService->GetPublicSuffixFromHost(cHost, publicSuffix); + + return NS_SUCCEEDED(rv) && !cHost.Equals(publicSuffix); + } + + return true; + }; + + bool SchemeInList(nsAString& scheme, const char** schemes) + { + for (; *schemes; schemes++) { + if (scheme.LowerCaseEqualsASCII(*schemes)) { + return true; + } + } + return false; + }; + + + // Formatters + + already_AddRefed + GetStringBundle() + { + nsCOMPtr sbs = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(sbs, nullptr); + + nsCOMPtr stringBundle; + sbs->CreateBundle("chrome://global/locale/extensions.properties", + getter_AddRefs(stringBundle)); + + return stringBundle.forget(); + }; + + void FormatErrorParams(const char* aName, const char16_t** aParams, int32_t aLength) + { + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr stringBundle = GetStringBundle(); + + if (stringBundle) { + NS_ConvertASCIItoUTF16 name(aName); + + rv = stringBundle->FormatStringFromName(name.get(), aParams, aLength, + getter_Copies(mError)); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + mError.AssignLiteral("An unexpected error occurred"); + } + }; + + + // Data members + + nsAutoString mURL; + NS_ConvertASCIItoUTF16 mDirective; + nsXPIDLString mError; + + bool mFoundSelf; +}; + +/** + * Validates a custom content security policy string for use by an add-on. + * In particular, ensures that: + * + * - Both object-src and script-src directives are present, and meet + * the policies required by the CSPValidator class + * + * - The script-src directive includes the source 'self' + */ +NS_IMETHODIMP +AddonContentPolicy::ValidateAddonCSP(const nsAString& aPolicyString, + nsAString& aResult) +{ + nsresult rv; + + // Validate against a randomly-generated extension origin. + // There is no add-on-specific behavior in the CSP code, beyond the ability + // for add-ons to specify a custom policy, but the parser requires a valid + // origin in order to operate correctly. + nsAutoString url(u"moz-extension://"); + { + nsCOMPtr uuidgen = services::GetUUIDGenerator(); + NS_ENSURE_TRUE(uuidgen, NS_ERROR_FAILURE); + + nsID id; + rv = uuidgen->GenerateUUIDInPlace(&id); + NS_ENSURE_SUCCESS(rv, rv); + + char idString[NSID_LENGTH]; + id.ToProvidedString(idString); + + MOZ_RELEASE_ASSERT(idString[0] == '{' && idString[NSID_LENGTH - 2] == '}', + "UUID generator did not return a valid UUID"); + + url.AppendASCII(idString + 1, NSID_LENGTH - 3); + } + + + RefPtr principal = + BasePrincipal::CreateCodebasePrincipal(NS_ConvertUTF16toUTF8(url)); + + nsCOMPtr csp; + rv = principal->EnsureCSP(nullptr, getter_AddRefs(csp)); + NS_ENSURE_SUCCESS(rv, rv); + + + csp->AppendPolicy(aPolicyString, false, false); + + const nsCSPPolicy* policy = csp->GetPolicy(0); + if (!policy) { + CSPValidator validator(url, nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE); + aResult.Assign(validator.GetError()); + return NS_OK; + } + + bool haveValidDefaultSrc = false; + { + CSPDirective directive = nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE; + CSPValidator validator(url, directive); + + haveValidDefaultSrc = policy->visitDirectiveSrcs(directive, &validator); + } + + aResult.SetIsVoid(true); + { + CSPDirective directive = nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE; + CSPValidator validator(url, directive, !haveValidDefaultSrc); + + if (!policy->visitDirectiveSrcs(directive, &validator)) { + aResult.Assign(validator.GetError()); + } else if (!validator.FoundSelf()) { + validator.FormatError("csp.error.missing-source", NS_LITERAL_STRING("'self'")); + aResult.Assign(validator.GetError()); + } + } + + if (aResult.IsVoid()) { + CSPDirective directive = nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE; + CSPValidator validator(url, directive, !haveValidDefaultSrc); + + if (!policy->visitDirectiveSrcs(directive, &validator)) { + aResult.Assign(validator.GetError()); + } + } + + return NS_OK; +} diff --git a/toolkit/mozapps/webextensions/AddonContentPolicy.h b/toolkit/mozapps/webextensions/AddonContentPolicy.h new file mode 100644 index 000000000..4c8af4828 --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonContentPolicy.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIContentPolicy.h" +#include "nsIAddonPolicyService.h" + +class AddonContentPolicy : public nsIContentPolicy, + public nsIAddonContentPolicy +{ +protected: + virtual ~AddonContentPolicy(); + +public: + AddonContentPolicy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPOLICY + NS_DECL_NSIADDONCONTENTPOLICY +}; diff --git a/toolkit/mozapps/webextensions/AddonManager.jsm b/toolkit/mozapps/webextensions/AddonManager.jsm new file mode 100644 index 000000000..c5cb80091 --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonManager.jsm @@ -0,0 +1,3674 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +// Cannot use Services.appinfo here, or else xpcshell-tests will blow up, as +// most tests later register different nsIAppInfo implementations, which +// wouldn't be reflected in Services.appinfo anymore, as the lazy getter +// underlying it would have been initialized if we used it here. +if ("@mozilla.org/xre/app-info;1" in Cc) { + let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); + if (runtime.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // Refuse to run in child processes. + throw new Error("You cannot use the AddonManager in child processes!"); + } +} + +Cu.import("resource://gre/modules/AppConstants.jsm"); + +const MOZ_COMPATIBILITY_NIGHTLY = !['aurora', 'beta', 'release', 'esr'].includes(AppConstants.MOZ_UPDATE_CHANNEL); + +const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion"; +const PREF_DEFAULT_PROVIDERS_ENABLED = "extensions.defaultProviders.enabled"; +const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; +const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; +const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion"; +const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; +const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility"; +const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; +const PREF_EM_UPDATE_BACKGROUND_URL = "extensions.update.background.url"; +const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; +const PREF_APP_UPDATE_AUTO = "app.update.auto"; +const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; +const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion"; +const PREF_EM_HOTFIX_URL = "extensions.hotfix.url"; +const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes"; +const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs."; +const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; +const PREF_SELECTED_LOCALE = "general.useragent.locale"; +const UNKNOWN_XPCOM_ABI = "unknownABI"; + +const PREF_MIN_WEBEXT_PLATFORM_VERSION = "extensions.webExtensionsMinPlatformVersion"; +const PREF_WEBAPI_TESTING = "extensions.webapi.testing"; + +const UPDATE_REQUEST_VERSION = 2; +const CATEGORY_UPDATE_PARAMS = "extension-update-params"; + +const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist"; + +const KEY_PROFILEDIR = "ProfD"; +const KEY_APPDIR = "XCurProcD"; +const FILE_BLOCKLIST = "blocklist.xml"; + +const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; +const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility"; +var PREF_EM_CHECK_COMPATIBILITY = MOZ_COMPATIBILITY_NIGHTLY ? + PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly" : + undefined; + +const TOOLKIT_ID = "toolkit@mozilla.org"; + +const VALID_TYPES_REGEXP = /^[\w\-]+$/; + +const WEBAPI_INSTALL_HOSTS = ["addons.mozilla.org", "testpilot.firefox.com"]; +const WEBAPI_TEST_INSTALL_HOSTS = [ + "addons.allizom.org", "addons-dev.allizom.org", + "testpilot.stage.mozaws.net", "testpilot.dev.mozaws.net", + "example.com", +]; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AsyncShutdown.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Promise", + "resource://gre/modules/Promise.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", + "resource://gre/modules/addons/AddonRepository.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Extension", + "resource://gre/modules/Extension.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "CertUtils", function() { + let certUtils = {}; + Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils); + return certUtils; +}); + +const INTEGER = /^[1-9]\d*$/; + +this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ]; + +const CATEGORY_PROVIDER_MODULE = "addon-provider-module"; + +// A list of providers to load by default +const DEFAULT_PROVIDERS = [ + "resource://gre/modules/addons/XPIProvider.jsm", + "resource://gre/modules/LightweightThemeManager.jsm" +]; + +Cu.import("resource://gre/modules/Log.jsm"); +// Configure a logger at the parent 'addons' level to format +// messages for all the modules under addons.* +const PARENT_LOGGER_ID = "addons"; +var parentLogger = Log.repository.getLogger(PARENT_LOGGER_ID); +parentLogger.level = Log.Level.Warn; +var formatter = new Log.BasicFormatter(); +// Set parent logger (and its children) to append to +// the Javascript section of the Browser Console +parentLogger.addAppender(new Log.ConsoleAppender(formatter)); +// Set parent logger (and its children) to +// also append to standard out +parentLogger.addAppender(new Log.DumpAppender(formatter)); + +// Create a new logger (child of 'addons' logger) +// for use by the Addons Manager +const LOGGER_ID = "addons.manager"; +var logger = Log.repository.getLogger(LOGGER_ID); + +// Provide the ability to enable/disable logging +// messages at runtime. +// If the "extensions.logging.enabled" preference is +// missing or 'false', messages at the WARNING and higher +// severity should be logged to the JS console and standard error. +// If "extensions.logging.enabled" is set to 'true', messages +// at DEBUG and higher should go to JS console and standard error. +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; + +const UNNAMED_PROVIDER = ""; +function providerName(aProvider) { + return aProvider.name || UNNAMED_PROVIDER; +} + +/** + * Preference listener which listens for a change in the + * "extensions.logging.enabled" preference and changes the logging level of the + * parent 'addons' level logger accordingly. + */ +var PrefObserver = { + init: function() { + Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); + Services.obs.addObserver(this, "xpcom-shutdown", false); + this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); + }, + + observe: function(aSubject, aTopic, aData) { + if (aTopic == "xpcom-shutdown") { + Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + } + else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { + let debugLogEnabled = false; + try { + debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); + } + catch (e) { + } + if (debugLogEnabled) { + parentLogger.level = Log.Level.Debug; + } + else { + parentLogger.level = Log.Level.Warn; + } + } + } +}; + +PrefObserver.init(); + +/** + * Calls a callback method consuming any thrown exception. Any parameters after + * the callback parameter will be passed to the callback. + * + * @param aCallback + * The callback method to call + */ +function safeCall(aCallback, ...aArgs) { + try { + aCallback.apply(null, aArgs); + } + catch (e) { + logger.warn("Exception calling callback", e); + } +} + +/** + * Creates a function that will call the passed callback catching and logging + * any exceptions. + * + * @param aCallback + * The callback method to call + */ +function makeSafe(aCallback) { + return function(...aArgs) { + safeCall(aCallback, ...aArgs); + } +} + +/** + * Report an exception thrown by a provider API method. + */ +function reportProviderError(aProvider, aMethod, aError) { + let method = `provider ${providerName(aProvider)}.${aMethod}`; + AddonManagerPrivate.recordException("AMI", method, aError); + logger.error("Exception calling " + method, aError); +} + +/** + * Calls a method on a provider if it exists and consumes any thrown exception. + * Any parameters after the aDefault parameter are passed to the provider's method. + * + * @param aProvider + * The provider to call + * @param aMethod + * The method name to call + * @param aDefault + * A default return value if the provider does not implement the named + * method or throws an error. + * @return the return value from the provider, or aDefault if the provider does not + * implement method or throws an error + */ +function callProvider(aProvider, aMethod, aDefault, ...aArgs) { + if (!(aMethod in aProvider)) + return aDefault; + + try { + return aProvider[aMethod].apply(aProvider, aArgs); + } + catch (e) { + reportProviderError(aProvider, aMethod, e); + return aDefault; + } +} + +/** + * Calls a method on a provider if it exists and consumes any thrown exception. + * Parameters after aMethod are passed to aProvider.aMethod(). + * The last parameter must be a callback function. + * If the provider does not implement the method, or the method throws, calls + * the callback with 'undefined'. + * + * @param aProvider + * The provider to call + * @param aMethod + * The method name to call + */ +function callProviderAsync(aProvider, aMethod, ...aArgs) { + let callback = aArgs[aArgs.length - 1]; + if (!(aMethod in aProvider)) { + callback(undefined); + return undefined; + } + try { + return aProvider[aMethod].apply(aProvider, aArgs); + } + catch (e) { + reportProviderError(aProvider, aMethod, e); + callback(undefined); + return undefined; + } +} + +/** + * Calls a method on a provider if it exists and consumes any thrown exception. + * Parameters after aMethod are passed to aProvider.aMethod() and an additional + * callback is added for the provider to return a result to. + * + * @param aProvider + * The provider to call + * @param aMethod + * The method name to call + * @return {Promise} + * @resolves The result the provider returns, or |undefined| if the provider + * does not implement the method or the method throws. + * @rejects Never + */ +function promiseCallProvider(aProvider, aMethod, ...aArgs) { + return new Promise(resolve => { + callProviderAsync(aProvider, aMethod, ...aArgs, resolve); + }); +} + +/** + * Gets the currently selected locale for display. + * @return the selected locale or "en-US" if none is selected + */ +function getLocale() { + try { + if (Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE)) + return Services.locale.getLocaleComponentForUserAgent(); + } + catch (e) { } + + try { + let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE, + Ci.nsIPrefLocalizedString); + if (locale) + return locale; + } + catch (e) { } + + try { + return Services.prefs.getCharPref(PREF_SELECTED_LOCALE); + } + catch (e) { } + + return "en-US"; +} + +function webAPIForAddon(addon) { + if (!addon) { + return null; + } + + let result = {}; + + // By default just pass through any plain property, the webidl will + // control access. Also filter out private properties, regular Addon + // objects are okay but MockAddon used in tests has non-serializable + // private properties. + for (let prop in addon) { + if (prop[0] != "_" && typeof(addon[prop]) != "function") { + result[prop] = addon[prop]; + } + } + + // A few properties are computed for a nicer API + result.isEnabled = !addon.userDisabled; + result.canUninstall = Boolean(addon.permissions & AddonManager.PERM_CAN_UNINSTALL); + + return result; +} + +/** + * A helper class to repeatedly call a listener with each object in an array + * optionally checking whether the object has a method in it. + * + * @param aObjects + * The array of objects to iterate through + * @param aMethod + * An optional method name, if not null any objects without this method + * will not be passed to the listener + * @param aListener + * A listener implementing nextObject and noMoreObjects methods. The + * former will be called with the AsyncObjectCaller as the first + * parameter and the object as the second. noMoreObjects will be passed + * just the AsyncObjectCaller + */ +function AsyncObjectCaller(aObjects, aMethod, aListener) { + this.objects = [...aObjects]; + this.method = aMethod; + this.listener = aListener; + + this.callNext(); +} + +AsyncObjectCaller.prototype = { + objects: null, + method: null, + listener: null, + + /** + * Passes the next object to the listener or calls noMoreObjects if there + * are none left. + */ + callNext: function() { + if (this.objects.length == 0) { + this.listener.noMoreObjects(this); + return; + } + + let object = this.objects.shift(); + if (!this.method || this.method in object) + this.listener.nextObject(this, object); + else + this.callNext(); + } +}; + +/** + * Listens for a browser changing origin and cancels the installs that were + * started by it. + */ +function BrowserListener(aBrowser, aInstallingPrincipal, aInstalls) { + this.browser = aBrowser; + this.principal = aInstallingPrincipal; + this.installs = aInstalls; + this.installCount = aInstalls.length; + + aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); + Services.obs.addObserver(this, "message-manager-close", true); + + for (let install of this.installs) + install.addListener(this); + + this.registered = true; +} + +BrowserListener.prototype = { + browser: null, + installs: null, + installCount: null, + registered: false, + + unregister: function() { + if (!this.registered) + return; + this.registered = false; + + Services.obs.removeObserver(this, "message-manager-close"); + // The browser may have already been detached + if (this.browser.removeProgressListener) + this.browser.removeProgressListener(this); + + for (let install of this.installs) + install.removeListener(this); + this.installs = null; + }, + + cancelInstalls: function() { + for (let install of this.installs) { + try { + install.cancel(); + } + catch (e) { + // Some installs may have already failed or been cancelled, ignore these + } + } + }, + + observe: function(subject, topic, data) { + if (subject != this.browser.messageManager) + return; + + // The browser's message manager has closed and so the browser is + // going away, cancel all installs + this.cancelInstalls(); + }, + + onLocationChange: function(webProgress, request, location) { + if (this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal)) + return; + + // The browser has navigated to a new origin so cancel all installs + this.cancelInstalls(); + }, + + onDownloadCancelled: function(install) { + // Don't need to hear more events from this install + install.removeListener(this); + + // Once all installs have ended unregister everything + if (--this.installCount == 0) + this.unregister(); + }, + + onDownloadFailed: function(install) { + this.onDownloadCancelled(install); + }, + + onInstallFailed: function(install) { + this.onDownloadCancelled(install); + }, + + onInstallEnded: function(install) { + this.onDownloadCancelled(install); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, + Ci.nsIWebProgressListener, + Ci.nsIObserver]) +}; + +/** + * This represents an author of an add-on (e.g. creator or developer) + * + * @param aName + * The name of the author + * @param aURL + * The URL of the author's profile page + */ +function AddonAuthor(aName, aURL) { + this.name = aName; + this.url = aURL; +} + +AddonAuthor.prototype = { + name: null, + url: null, + + // Returns the author's name, defaulting to the empty string + toString: function() { + return this.name || ""; + } +} + +/** + * This represents an screenshot for an add-on + * + * @param aURL + * The URL to the full version of the screenshot + * @param aWidth + * The width in pixels of the screenshot + * @param aHeight + * The height in pixels of the screenshot + * @param aThumbnailURL + * The URL to the thumbnail version of the screenshot + * @param aThumbnailWidth + * The width in pixels of the thumbnail version of the screenshot + * @param aThumbnailHeight + * The height in pixels of the thumbnail version of the screenshot + * @param aCaption + * The caption of the screenshot + */ +function AddonScreenshot(aURL, aWidth, aHeight, aThumbnailURL, + aThumbnailWidth, aThumbnailHeight, aCaption) { + this.url = aURL; + if (aWidth) this.width = aWidth; + if (aHeight) this.height = aHeight; + if (aThumbnailURL) this.thumbnailURL = aThumbnailURL; + if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth; + if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight; + if (aCaption) this.caption = aCaption; +} + +AddonScreenshot.prototype = { + url: null, + width: null, + height: null, + thumbnailURL: null, + thumbnailWidth: null, + thumbnailHeight: null, + caption: null, + + // Returns the screenshot URL, defaulting to the empty string + toString: function() { + return this.url || ""; + } +} + + +/** + * This represents a compatibility override for an addon. + * + * @param aType + * Overrride type - "compatible" or "incompatible" + * @param aMinVersion + * Minimum version of the addon to match + * @param aMaxVersion + * Maximum version of the addon to match + * @param aAppID + * Application ID used to match appMinVersion and appMaxVersion + * @param aAppMinVersion + * Minimum version of the application to match + * @param aAppMaxVersion + * Maximum version of the application to match + */ +function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID, + aAppMinVersion, aAppMaxVersion) { + this.type = aType; + this.minVersion = aMinVersion; + this.maxVersion = aMaxVersion; + this.appID = aAppID; + this.appMinVersion = aAppMinVersion; + this.appMaxVersion = aAppMaxVersion; +} + +AddonCompatibilityOverride.prototype = { + /** + * Type of override - "incompatible" or "compatible". + * Only "incompatible" is supported for now. + */ + type: null, + + /** + * Min version of the addon to match. + */ + minVersion: null, + + /** + * Max version of the addon to match. + */ + maxVersion: null, + + /** + * Application ID to match. + */ + appID: null, + + /** + * Min version of the application to match. + */ + appMinVersion: null, + + /** + * Max version of the application to match. + */ + appMaxVersion: null +}; + + +/** + * A type of add-on, used by the UI to determine how to display different types + * of add-ons. + * + * @param aID + * The add-on type ID + * @param aLocaleURI + * The URI of a localized properties file to get the displayable name + * for the type from + * @param aLocaleKey + * The key for the string in the properties file or the actual display + * name if aLocaleURI is null. Include %ID% to include the type ID in + * the key + * @param aViewType + * The optional type of view to use in the UI + * @param aUIPriority + * The priority is used by the UI to list the types in order. Lower + * values push the type higher in the list. + * @param aFlags + * An option set of flags that customize the display of the add-on in + * the UI. + */ +function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) { + if (!aID) + throw Components.Exception("An AddonType must have an ID", Cr.NS_ERROR_INVALID_ARG); + + if (aViewType && aUIPriority === undefined) + throw Components.Exception("An AddonType with a defined view must have a set UI priority", + Cr.NS_ERROR_INVALID_ARG); + + if (!aLocaleKey) + throw Components.Exception("An AddonType must have a displayable name", + Cr.NS_ERROR_INVALID_ARG); + + this.id = aID; + this.uiPriority = aUIPriority; + this.viewType = aViewType; + this.flags = aFlags; + + if (aLocaleURI) { + XPCOMUtils.defineLazyGetter(this, "name", () => { + let bundle = Services.strings.createBundle(aLocaleURI); + return bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID)); + }); + } + else { + this.name = aLocaleKey; + } +} + +var gStarted = false; +var gStartupComplete = false; +var gCheckCompatibility = true; +var gStrictCompatibility = true; +var gCheckUpdateSecurityDefault = true; +var gCheckUpdateSecurity = gCheckUpdateSecurityDefault; +var gUpdateEnabled = true; +var gAutoUpdateDefault = true; +var gHotfixID = null; +var gWebExtensionsMinPlatformVersion = null; +var gShutdownBarrier = null; +var gRepoShutdownState = ""; +var gShutdownInProgress = false; +var gPluginPageListener = null; + +/** + * This is the real manager, kept here rather than in AddonManager to keep its + * contents hidden from API users. + */ +var AddonManagerInternal = { + managerListeners: [], + installListeners: [], + addonListeners: [], + typeListeners: [], + pendingProviders: new Set(), + providers: new Set(), + providerShutdowns: new Map(), + types: {}, + startupChanges: {}, + // Store telemetry details per addon provider + telemetryDetails: {}, + upgradeListeners: new Map(), + + recordTimestamp: function(name, value) { + this.TelemetryTimestamps.add(name, value); + }, + + validateBlocklist: function() { + let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]); + + // If there is no application shipped blocklist then there is nothing to do + if (!appBlocklist.exists()) + return; + + let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]); + + // If there is no blocklist in the profile then copy the application shipped + // one there + if (!profileBlocklist.exists()) { + try { + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); + } + catch (e) { + logger.warn("Failed to copy the application shipped blocklist to the profile", e); + } + return; + } + + let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + try { + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + fileStream.init(appBlocklist, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); + cstream.init(fileStream, "UTF-8", 0, 0); + + let data = ""; + let str = {}; + let read = 0; + do { + read = cstream.readString(0xffffffff, str); + data += str.value; + } while (read != 0); + + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); + var doc = parser.parseFromString(data, "text/xml"); + } + catch (e) { + logger.warn("Application shipped blocklist could not be loaded", e); + return; + } + finally { + try { + fileStream.close(); + } + catch (e) { + logger.warn("Unable to close blocklist file stream", e); + } + } + + // If the namespace is incorrect then ignore the application shipped + // blocklist + if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) { + logger.warn("Application shipped blocklist has an unexpected namespace (" + + doc.documentElement.namespaceURI + ")"); + return; + } + + // If there is no lastupdate information then ignore the application shipped + // blocklist + if (!doc.documentElement.hasAttribute("lastupdate")) + return; + + // If the application shipped blocklist is older than the profile blocklist + // then do nothing + if (doc.documentElement.getAttribute("lastupdate") <= + profileBlocklist.lastModifiedTime) + return; + + // Otherwise copy the application shipped blocklist to the profile + try { + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); + } + catch (e) { + logger.warn("Failed to copy the application shipped blocklist to the profile", e); + } + }, + + /** + * Start up a provider, and register its shutdown hook if it has one + */ + _startProvider(aProvider, aAppChanged, aOldAppVersion, aOldPlatformVersion) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + logger.debug(`Starting provider: ${providerName(aProvider)}`); + callProvider(aProvider, "startup", null, aAppChanged, aOldAppVersion, aOldPlatformVersion); + if ('shutdown' in aProvider) { + let name = providerName(aProvider); + let AMProviderShutdown = () => { + // If the provider has been unregistered, it will have been removed from + // this.providers. If it hasn't been unregistered, then this is a normal + // shutdown - and we move it to this.pendingProviders incase we're + // running in a test that will start AddonManager again. + if (this.providers.has(aProvider)) { + this.providers.delete(aProvider); + this.pendingProviders.add(aProvider); + } + + return new Promise((resolve, reject) => { + logger.debug("Calling shutdown blocker for " + name); + resolve(aProvider.shutdown()); + }) + .catch(err => { + logger.warn("Failure during shutdown of " + name, err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of " + name, err); + }); + }; + logger.debug("Registering shutdown blocker for " + name); + this.providerShutdowns.set(aProvider, AMProviderShutdown); + AddonManager.shutdown.addBlocker(name, AMProviderShutdown); + } + + this.pendingProviders.delete(aProvider); + this.providers.add(aProvider); + logger.debug(`Provider finished startup: ${providerName(aProvider)}`); + }, + + _getProviderByName(aName) { + for (let provider of this.providers) { + if (providerName(provider) == aName) + return provider; + } + return undefined; + }, + + /** + * Initializes the AddonManager, loading any known providers and initializing + * them. + */ + startup: function() { + try { + if (gStarted) + return; + + this.recordTimestamp("AMI_startup_begin"); + + // clear this for xpcshell test restarts + for (let provider in this.telemetryDetails) + delete this.telemetryDetails[provider]; + + let appChanged = undefined; + + let oldAppVersion = null; + try { + oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); + appChanged = Services.appinfo.version != oldAppVersion; + } + catch (e) { } + + Extension.browserUpdated = appChanged; + + let oldPlatformVersion = null; + try { + oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION); + } + catch (e) { } + + if (appChanged !== false) { + logger.debug("Application has been upgraded"); + Services.prefs.setCharPref(PREF_EM_LAST_APP_VERSION, + Services.appinfo.version); + Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION, + Services.appinfo.platformVersion); + Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, + (appChanged === undefined ? 0 : -1)); + this.validateBlocklist(); + } + + if (!MOZ_COMPATIBILITY_NIGHTLY) { + PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." + + Services.appinfo.version.replace(BRANCH_REGEXP, "$1"); + } + + try { + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_CHECK_COMPATIBILITY, this, false); + + try { + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_STRICT_COMPATIBILITY, this, false); + + try { + let defaultBranch = Services.prefs.getDefaultBranch(""); + gCheckUpdateSecurityDefault = defaultBranch.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch (e) {} + + try { + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_CHECK_UPDATE_SECURITY, this, false); + + try { + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_UPDATE_ENABLED, this, false); + + try { + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false); + + try { + gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false); + + try { + gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION); + } catch (e) {} + Services.prefs.addObserver(PREF_MIN_WEBEXT_PLATFORM_VERSION, this, false); + + let defaultProvidersEnabled = true; + try { + defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED); + } catch (e) {} + AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled); + + // Ensure all default providers have had a chance to register themselves + if (defaultProvidersEnabled) { + for (let url of DEFAULT_PROVIDERS) { + try { + let scope = {}; + Components.utils.import(url, scope); + // Sanity check - make sure the provider exports a symbol that + // has a 'startup' method + let syms = Object.keys(scope); + if ((syms.length < 1) || + (typeof scope[syms[0]].startup != "function")) { + logger.warn("Provider " + url + " has no startup()"); + AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()"); + } + logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource()); + } + catch (e) { + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); + logger.error("Exception loading default provider \"" + url + "\"", e); + } + } + } + + // Load any providers registered in the category manager + let catman = Cc["@mozilla.org/categorymanager;1"]. + getService(Ci.nsICategoryManager); + let entries = catman.enumerateCategory(CATEGORY_PROVIDER_MODULE); + while (entries.hasMoreElements()) { + let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; + let url = catman.getCategoryEntry(CATEGORY_PROVIDER_MODULE, entry); + + try { + Components.utils.import(url, {}); + logger.debug(`Loaded provider scope for ${url}`); + } + catch (e) { + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); + logger.error("Exception loading provider " + entry + " from category \"" + + url + "\"", e); + } + } + + // Register our shutdown handler with the AsyncShutdown manager + gShutdownBarrier = new AsyncShutdown.Barrier("AddonManager: Waiting for providers to shut down."); + AsyncShutdown.profileBeforeChange.addBlocker("AddonManager: shutting down.", + this.shutdownManager.bind(this), + {fetchState: this.shutdownState.bind(this)}); + + // Once we start calling providers we must allow all normal methods to work. + gStarted = true; + + for (let provider of this.pendingProviders) { + this._startProvider(provider, appChanged, oldAppVersion, oldPlatformVersion); + } + + // If this is a new profile just pretend that there were no changes + if (appChanged === undefined) { + for (let type in this.startupChanges) + delete this.startupChanges[type]; + } + + // Support for remote about:plugins. Note that this module isn't loaded + // at the top because Services.appinfo is defined late in tests. + let { RemotePages } = Cu.import("resource://gre/modules/RemotePageManager.jsm", {}); + + gPluginPageListener = new RemotePages("about:plugins"); + gPluginPageListener.addMessageListener("RequestPlugins", this.requestPlugins); + + gStartupComplete = true; + this.recordTimestamp("AMI_startup_end"); + } + catch (e) { + logger.error("startup failed", e); + AddonManagerPrivate.recordException("AMI", "startup failed", e); + } + + logger.debug("Completed startup sequence"); + this.callManagerListeners("onStartup"); + }, + + /** + * Registers a new AddonProvider. + * + * @param aProvider + * The provider to register + * @param aTypes + * An optional array of add-on types + */ + registerProvider: function(aProvider, aTypes) { + if (!aProvider || typeof aProvider != "object") + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + this.pendingProviders.add(aProvider); + + if (aTypes) { + for (let type of aTypes) { + if (!(type.id in this.types)) { + if (!VALID_TYPES_REGEXP.test(type.id)) { + logger.warn("Ignoring invalid type " + type.id); + return; + } + + this.types[type.id] = { + type: type, + providers: [aProvider] + }; + + let typeListeners = this.typeListeners.slice(0); + for (let listener of typeListeners) + safeCall(() => listener.onTypeAdded(type)); + } + else { + this.types[type.id].providers.push(aProvider); + } + } + } + + // If we're registering after startup call this provider's startup. + if (gStarted) { + this._startProvider(aProvider); + } + }, + + /** + * Unregisters an AddonProvider. + * + * @param aProvider + * The provider to unregister + * @return Whatever the provider's 'shutdown' method returns (if anything). + * For providers that have async shutdown methods returning Promises, + * the caller should wait for that Promise to resolve. + */ + unregisterProvider: function(aProvider) { + if (!aProvider || typeof aProvider != "object") + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + + this.providers.delete(aProvider); + // The test harness will unregister XPIProvider *after* shutdown, which is + // after the provider will have been moved from providers to + // pendingProviders. + this.pendingProviders.delete(aProvider); + + for (let type in this.types) { + this.types[type].providers = this.types[type].providers.filter(p => p != aProvider); + if (this.types[type].providers.length == 0) { + let oldType = this.types[type].type; + delete this.types[type]; + + let typeListeners = this.typeListeners.slice(0); + for (let listener of typeListeners) + safeCall(() => listener.onTypeRemoved(oldType)); + } + } + + // If we're unregistering after startup but before shutting down, + // remove the blocker for this provider's shutdown and call it. + // If we're already shutting down, just let gShutdownBarrier call it to avoid races. + if (gStarted && !gShutdownInProgress) { + logger.debug("Unregistering shutdown blocker for " + providerName(aProvider)); + let shutter = this.providerShutdowns.get(aProvider); + if (shutter) { + this.providerShutdowns.delete(aProvider); + gShutdownBarrier.client.removeBlocker(shutter); + return shutter(); + } + } + return undefined; + }, + + /** + * Mark a provider as safe to access via AddonManager APIs, before its + * startup has completed. + * + * Normally a provider isn't marked as safe until after its (synchronous) + * startup() method has returned. Until a provider has been marked safe, + * it won't be used by any of the AddonManager APIs. markProviderSafe() + * allows a provider to mark itself as safe during its startup; this can be + * useful if the provider wants to perform tasks that block startup, which + * happen after its required initialization tasks and therefore when the + * provider is in a safe state. + * + * @param aProvider Provider object to mark safe + */ + markProviderSafe: function(aProvider) { + if (!gStarted) { + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + } + + if (!aProvider || typeof aProvider != "object") { + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + } + + if (!this.pendingProviders.has(aProvider)) { + return; + } + + this.pendingProviders.delete(aProvider); + this.providers.add(aProvider); + }, + + /** + * Calls a method on all registered providers if it exists and consumes any + * thrown exception. Return values are ignored. Any parameters after the + * method parameter are passed to the provider's method. + * WARNING: Do not use for asynchronous calls; callProviders() does not + * invoke callbacks if provider methods throw synchronous exceptions. + * + * @param aMethod + * The method name to call + * @see callProvider + */ + callProviders: function(aMethod, ...aArgs) { + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + try { + if (aMethod in provider) + provider[aMethod].apply(provider, aArgs); + } + catch (e) { + reportProviderError(provider, aMethod, e); + } + } + }, + + /** + * Report the current state of asynchronous shutdown + */ + shutdownState() { + let state = []; + if (gShutdownBarrier) { + state.push({ + name: gShutdownBarrier.client.name, + state: gShutdownBarrier.state + }); + } + state.push({ + name: "AddonRepository: async shutdown", + state: gRepoShutdownState + }); + return state; + }, + + /** + * Shuts down the addon manager and all registered providers, this must clean + * up everything in order for automated tests to fake restarts. + * @return Promise{null} that resolves when all providers and dependent modules + * have finished shutting down + */ + shutdownManager: Task.async(function*() { + logger.debug("shutdown"); + this.callManagerListeners("onShutdown"); + + gRepoShutdownState = "pending"; + gShutdownInProgress = true; + // Clean up listeners + Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this); + Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this); + Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this); + Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this); + Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this); + Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this); + gPluginPageListener.destroy(); + gPluginPageListener = null; + + let savedError = null; + // Only shut down providers if they've been started. + if (gStarted) { + try { + yield gShutdownBarrier.wait(); + } + catch (err) { + savedError = err; + logger.error("Failure during wait for shutdown barrier", err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonManager providers", err); + } + } + + // Shut down AddonRepository after providers (if any). + try { + gRepoShutdownState = "in progress"; + yield AddonRepository.shutdown(); + gRepoShutdownState = "done"; + } + catch (err) { + savedError = err; + logger.error("Failure during AddonRepository shutdown", err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonRepository", err); + } + + logger.debug("Async provider shutdown done"); + this.managerListeners.splice(0, this.managerListeners.length); + this.installListeners.splice(0, this.installListeners.length); + this.addonListeners.splice(0, this.addonListeners.length); + this.typeListeners.splice(0, this.typeListeners.length); + this.providerShutdowns.clear(); + for (let type in this.startupChanges) + delete this.startupChanges[type]; + gStarted = false; + gStartupComplete = false; + gShutdownBarrier = null; + gShutdownInProgress = false; + if (savedError) { + throw savedError; + } + }), + + requestPlugins: function({ target: port }) { + // Lists all the properties that plugins.html needs + const NEEDED_PROPS = ["name", "pluginLibraries", "pluginFullpath", "version", + "isActive", "blocklistState", "description", + "pluginMimeTypes"]; + function filterProperties(plugin) { + let filtered = {}; + for (let prop of NEEDED_PROPS) { + filtered[prop] = plugin[prop]; + } + return filtered; + } + + AddonManager.getAddonsByTypes(["plugin"], function(aPlugins) { + port.sendAsyncMessage("PluginList", aPlugins.map(filterProperties)); + }); + }, + + /** + * Notified when a preference we're interested in has changed. + * + * @see nsIObserver + */ + observe: function(aSubject, aTopic, aData) { + switch (aData) { + case PREF_EM_CHECK_COMPATIBILITY: { + let oldValue = gCheckCompatibility; + try { + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); + } catch (e) { + gCheckCompatibility = true; + } + + this.callManagerListeners("onCompatibilityModeChanged"); + + if (gCheckCompatibility != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_STRICT_COMPATIBILITY: { + let oldValue = gStrictCompatibility; + try { + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); + } catch (e) { + gStrictCompatibility = true; + } + + this.callManagerListeners("onCompatibilityModeChanged"); + + if (gStrictCompatibility != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_CHECK_UPDATE_SECURITY: { + let oldValue = gCheckUpdateSecurity; + try { + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch (e) { + gCheckUpdateSecurity = true; + } + + this.callManagerListeners("onCheckUpdateSecurityChanged"); + + if (gCheckUpdateSecurity != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_UPDATE_ENABLED: { + let oldValue = gUpdateEnabled; + try { + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); + } catch (e) { + gUpdateEnabled = true; + } + + this.callManagerListeners("onUpdateModeChanged"); + break; + } + case PREF_EM_AUTOUPDATE_DEFAULT: { + let oldValue = gAutoUpdateDefault; + try { + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); + } catch (e) { + gAutoUpdateDefault = true; + } + + this.callManagerListeners("onUpdateModeChanged"); + break; + } + case PREF_EM_HOTFIX_ID: { + try { + gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); + } catch (e) { + gHotfixID = null; + } + break; + } + case PREF_MIN_WEBEXT_PLATFORM_VERSION: { + gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION); + break; + } + } + }, + + /** + * Replaces %...% strings in an addon url (update and updateInfo) with + * appropriate values. + * + * @param aAddon + * The Addon representing the add-on + * @param aUri + * The string representation of the URI to escape + * @param aAppVersion + * The optional application version to use for %APP_VERSION% + * @return The appropriately escaped URI. + */ + escapeAddonURI: function(aAddon, aUri, aAppVersion) + { + if (!aAddon || typeof aAddon != "object") + throw Components.Exception("aAddon must be an Addon object", + Cr.NS_ERROR_INVALID_ARG); + + if (!aUri || typeof aUri != "string") + throw Components.Exception("aUri must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aAppVersion && typeof aAppVersion != "string") + throw Components.Exception("aAppVersion must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled" + : "userEnabled"; + + if (!aAddon.isCompatible) + addonStatus += ",incompatible"; + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) + addonStatus += ",blocklisted"; + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + addonStatus += ",softblocked"; + + try { + var xpcomABI = Services.appinfo.XPCOMABI; + } catch (ex) { + xpcomABI = UNKNOWN_XPCOM_ABI; + } + + let uri = aUri.replace(/%ITEM_ID%/g, aAddon.id); + uri = uri.replace(/%ITEM_VERSION%/g, aAddon.version); + uri = uri.replace(/%ITEM_STATUS%/g, addonStatus); + uri = uri.replace(/%APP_ID%/g, Services.appinfo.ID); + uri = uri.replace(/%APP_VERSION%/g, aAppVersion ? aAppVersion : + Services.appinfo.version); + uri = uri.replace(/%REQ_VERSION%/g, UPDATE_REQUEST_VERSION); + uri = uri.replace(/%APP_OS%/g, Services.appinfo.OS); + uri = uri.replace(/%APP_ABI%/g, xpcomABI); + uri = uri.replace(/%APP_LOCALE%/g, getLocale()); + uri = uri.replace(/%CURRENT_APP_VERSION%/g, Services.appinfo.version); + + // Replace custom parameters (names of custom parameters must have at + // least 3 characters to prevent lookups for something like %D0%C8) + var catMan = null; + uri = uri.replace(/%(\w{3,})%/g, function(aMatch, aParam) { + if (!catMan) { + catMan = Cc["@mozilla.org/categorymanager;1"]. + getService(Ci.nsICategoryManager); + } + + try { + var contractID = catMan.getCategoryEntry(CATEGORY_UPDATE_PARAMS, aParam); + var paramHandler = Cc[contractID].getService(Ci.nsIPropertyBag2); + return paramHandler.getPropertyAsAString(aParam); + } + catch (e) { + return aMatch; + } + }); + + // escape() does not properly encode + symbols in any embedded FVF strings. + return uri.replace(/\+/g, "%2B"); + }, + + /** + * Performs a background update check by starting an update for all add-ons + * that can be updated. + * @return Promise{null} Resolves when the background update check is complete + * (the resulting addon installations may still be in progress). + */ + backgroundUpdateCheck: function() { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + let buPromise = Task.spawn(function*() { + let hotfixID = this.hotfixID; + + let appUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && + Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); + let checkHotfix = hotfixID && appUpdateEnabled; + + logger.debug("Background update check beginning"); + + Services.obs.notifyObservers(null, "addons-background-update-start", null); + + if (this.updateEnabled) { + let scope = {}; + Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope); + scope.LightweightThemeManager.updateCurrentTheme(); + + let allAddons = yield new Promise((resolve, reject) => this.getAllAddons(resolve)); + + // Repopulate repository cache first, to ensure compatibility overrides + // are up to date before checking for addon updates. + yield AddonRepository.backgroundUpdateCheck(); + + // Keep track of all the async add-on updates happening in parallel + let updates = []; + + for (let addon of allAddons) { + if (addon.id == hotfixID) { + continue; + } + + // Check all add-ons for updates so that any compatibility updates will + // be applied + updates.push(new Promise((resolve, reject) => { + addon.findUpdates({ + onUpdateAvailable: function(aAddon, aInstall) { + // Start installing updates when the add-on can be updated and + // background updates should be applied. + logger.debug("Found update for add-on ${id}", aAddon); + if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE && + AddonManager.shouldAutoUpdate(aAddon)) { + // XXX we really should resolve when this install is done, + // not when update-available check completes, no? + logger.debug(`Starting upgrade install of ${aAddon.id}`); + aInstall.install(); + } + }, + + onUpdateFinished: aAddon => { logger.debug("onUpdateFinished for ${id}", aAddon); resolve(); } + }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE); + })); + } + yield Promise.all(updates); + } + + if (checkHotfix) { + var hotfixVersion = ""; + try { + hotfixVersion = Services.prefs.getCharPref(PREF_EM_HOTFIX_LASTVERSION); + } + catch (e) { } + + let url = null; + if (Services.prefs.getPrefType(PREF_EM_HOTFIX_URL) == Ci.nsIPrefBranch.PREF_STRING) + url = Services.prefs.getCharPref(PREF_EM_HOTFIX_URL); + else + url = Services.prefs.getCharPref(PREF_EM_UPDATE_BACKGROUND_URL); + + // Build the URI from a fake add-on data. + url = AddonManager.escapeAddonURI({ + id: hotfixID, + version: hotfixVersion, + userDisabled: false, + appDisabled: false + }, url); + + Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm"); + let update = null; + try { + let foundUpdates = yield new Promise((resolve, reject) => { + AddonUpdateChecker.checkForUpdates(hotfixID, null, url, { + onUpdateCheckComplete: resolve, + onUpdateCheckError: reject + }); + }); + update = AddonUpdateChecker.getNewestCompatibleUpdate(foundUpdates); + } catch (e) { + // AUC.checkForUpdates already logged the error + } + + // Check that we have a hotfix update, and it's newer than the one we already + // have installed (if any) + if (update) { + if (Services.vc.compare(hotfixVersion, update.version) < 0) { + logger.debug("Downloading hotfix version " + update.version); + let aInstall = yield new Promise((resolve, reject) => + AddonManager.getInstallForURL(update.updateURL, resolve, + "application/x-xpinstall", update.updateHash, null, + null, update.version)); + + aInstall.addListener({ + onDownloadEnded: function(aInstall) { + if (aInstall.addon.id != hotfixID) { + logger.warn("The downloaded hotfix add-on did not have the " + + "expected ID and so will not be installed."); + aInstall.cancel(); + return; + } + + // If XPIProvider has reported the hotfix as properly signed then + // there is nothing more to do here + if (aInstall.addon.signedState == AddonManager.SIGNEDSTATE_SIGNED) + return; + + try { + if (!Services.prefs.getBoolPref(PREF_EM_CERT_CHECKATTRIBUTES)) + return; + } + catch (e) { + // By default don't do certificate checks. + return; + } + + try { + CertUtils.validateCert(aInstall.certificate, + CertUtils.readCertPrefs(PREF_EM_HOTFIX_CERTS)); + } + catch (e) { + logger.warn("The hotfix add-on was not signed by the expected " + + "certificate and so will not be installed.", e); + aInstall.cancel(); + } + }, + + onInstallEnded: function(aInstall) { + // Remember the last successfully installed version. + Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, + aInstall.version); + }, + + onInstallCancelled: function(aInstall) { + // Revert to the previous version if the installation was + // cancelled. + Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, + hotfixVersion); + } + }); + + aInstall.install(); + } + } + } + + if (appUpdateEnabled) { + try { + yield AddonManagerInternal._getProviderByName("XPIProvider").updateSystemAddons(); + } + catch (e) { + logger.warn("Failed to update system addons", e); + } + } + + logger.debug("Background update check complete"); + Services.obs.notifyObservers(null, + "addons-background-update-complete", + null); + }.bind(this)); + // Fork the promise chain so we can log the error and let our caller see it too. + buPromise.then(null, e => logger.warn("Error in background update", e)); + return buPromise; + }, + + /** + * Adds a add-on to the list of detected changes for this startup. If + * addStartupChange is called multiple times for the same add-on in the same + * startup then only the most recent change will be remembered. + * + * @param aType + * The type of change as a string. Providers can define their own + * types of changes or use the existing defined STARTUP_CHANGE_* + * constants + * @param aID + * The ID of the add-on + */ + addStartupChange: function(aType, aID) { + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (gStartupComplete) + return; + logger.debug("Registering startup change '" + aType + "' for " + aID); + + // Ensure that an ID is only listed in one type of change + for (let type in this.startupChanges) + this.removeStartupChange(type, aID); + + if (!(aType in this.startupChanges)) + this.startupChanges[aType] = []; + this.startupChanges[aType].push(aID); + }, + + /** + * Removes a startup change for an add-on. + * + * @param aType + * The type of change + * @param aID + * The ID of the add-on + */ + removeStartupChange: function(aType, aID) { + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (gStartupComplete) + return; + + if (!(aType in this.startupChanges)) + return; + + this.startupChanges[aType] = this.startupChanges[aType].filter(aItem => aItem != aID); + }, + + /** + * Calls all registered AddonManagerListeners with an event. Any parameters + * after the method parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + */ + callManagerListeners: function(aMethod, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let managerListeners = this.managerListeners.slice(0); + for (let listener of managerListeners) { + try { + if (aMethod in listener) + listener[aMethod].apply(listener, aArgs); + } + catch (e) { + logger.warn("AddonManagerListener threw exception when calling " + aMethod, e); + } + } + }, + + /** + * Calls all registered InstallListeners with an event. Any parameters after + * the extraListeners parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + * @param aExtraListeners + * An optional array of extra InstallListeners to also call + * @return false if any of the listeners returned false, true otherwise + */ + callInstallListeners: function(aMethod, + aExtraListeners, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aExtraListeners && !Array.isArray(aExtraListeners)) + throw Components.Exception("aExtraListeners must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + let result = true; + let listeners; + if (aExtraListeners) + listeners = aExtraListeners.concat(this.installListeners); + else + listeners = this.installListeners.slice(0); + + for (let listener of listeners) { + try { + if (aMethod in listener) { + if (listener[aMethod].apply(listener, aArgs) === false) + result = false; + } + } + catch (e) { + logger.warn("InstallListener threw exception when calling " + aMethod, e); + } + } + return result; + }, + + /** + * Calls all registered AddonListeners with an event. Any parameters after + * the method parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + */ + callAddonListeners: function(aMethod, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let addonListeners = this.addonListeners.slice(0); + for (let listener of addonListeners) { + try { + if (aMethod in listener) + listener[aMethod].apply(listener, aArgs); + } + catch (e) { + logger.warn("AddonListener threw exception when calling " + aMethod, e); + } + } + }, + + /** + * Notifies all providers that an add-on has been enabled when that type of + * add-on only supports a single add-on being enabled at a time. This allows + * the providers to disable theirs if necessary. + * + * @param aID + * The ID of the enabled add-on + * @param aType + * The type of the enabled add-on + * @param aPendingRestart + * A boolean indicating if the change will only take place the next + * time the application is restarted + */ + notifyAddonChanged: function(aID, aType, aPendingRestart) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aID && typeof aID != "string") + throw Components.Exception("aID must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + // Temporary hack until bug 520124 lands. + // We can get here during synchronous startup, at which point it's + // considered unsafe (and therefore disallowed by AddonManager.jsm) to + // access providers that haven't been initialized yet. Since this is when + // XPIProvider is starting up, XPIProvider can't access itself via APIs + // going through AddonManager.jsm. Furthermore, LightweightThemeManager may + // not be initialized until after XPIProvider is, and therefore would also + // be unaccessible during XPIProvider startup. Thankfully, these are the + // only two uses of this API, and we know it's safe to use this API with + // both providers; so we have this hack to allow bypassing the normal + // safetey guard. + // The notifyAddonChanged/addonChanged API will be unneeded and therefore + // removed by bug 520124, so this is a temporary quick'n'dirty hack. + let providers = [...this.providers, ...this.pendingProviders]; + for (let provider of providers) { + callProvider(provider, "addonChanged", null, aID, aType, aPendingRestart); + } + }, + + /** + * Notifies all providers they need to update the appDisabled property for + * their add-ons in response to an application change such as a blocklist + * update. + */ + updateAddonAppDisabledStates: function() { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + this.callProviders("updateAddonAppDisabledStates"); + }, + + /** + * Notifies all providers that the repository has updated its data for + * installed add-ons. + * + * @param aCallback + * Function to call when operation is complete. + */ + updateAddonRepositoryData: function(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", { + nextObject: function(aCaller, aProvider) { + callProviderAsync(aProvider, "updateAddonRepositoryData", + aCaller.callNext.bind(aCaller)); + }, + noMoreObjects: function(aCaller) { + safeCall(aCallback); + // only tests should care about this + Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null); + } + }); + }, + + /** + * Asynchronously gets an AddonInstall for a URL. + * + * @param aUrl + * The string represenation of the URL the add-on is located at + * @param aCallback + * A callback to pass the AddonInstall to + * @param aMimetype + * The mimetype of the add-on + * @param aHash + * An optional hash of the add-on + * @param aName + * An optional placeholder name while the add-on is being downloaded + * @param aIcons + * Optional placeholder icons while the add-on is being downloaded + * @param aVersion + * An optional placeholder version while the add-on is being downloaded + * @param aLoadGroup + * An optional nsILoadGroup to associate any network requests with + * @throws if the aUrl, aCallback or aMimetype arguments are not specified + */ + getInstallForURL: function(aUrl, aCallback, aMimetype, + aHash, aName, aIcons, + aVersion, aBrowser) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aUrl || typeof aUrl != "string") + throw Components.Exception("aURL must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aHash && typeof aHash != "string") + throw Components.Exception("aHash must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aName && typeof aName != "string") + throw Components.Exception("aName must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aIcons) { + if (typeof aIcons == "string") + aIcons = { "32": aIcons }; + else if (typeof aIcons != "object") + throw Components.Exception("aIcons must be a string, an object or null", + Cr.NS_ERROR_INVALID_ARG); + } else { + aIcons = {}; + } + + if (aVersion && typeof aVersion != "string") + throw Components.Exception("aVersion must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aBrowser && (!(aBrowser instanceof Ci.nsIDOMElement))) + throw Components.Exception("aBrowser must be a nsIDOMElement or null", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype)) { + callProviderAsync(provider, "getInstallForURL", + aUrl, aHash, aName, aIcons, aVersion, aBrowser, + function getInstallForURL_safeCall(aInstall) { + safeCall(aCallback, aInstall); + }); + return; + } + } + safeCall(aCallback, null); + }, + + /** + * Asynchronously gets an AddonInstall for an nsIFile. + * + * @param aFile + * The nsIFile where the add-on is located + * @param aCallback + * A callback to pass the AddonInstall to + * @param aMimetype + * An optional mimetype hint for the add-on + * @throws if the aFile or aCallback arguments are not specified + */ + getInstallForFile: function(aFile, aCallback, aMimetype) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!(aFile instanceof Ci.nsIFile)) + throw Components.Exception("aFile must be a nsIFile", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + if (aMimetype && typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "getInstallForFile", { + nextObject: function(aCaller, aProvider) { + callProviderAsync(aProvider, "getInstallForFile", aFile, + function(aInstall) { + if (aInstall) + safeCall(aCallback, aInstall); + else + aCaller.callNext(); + }); + }, + + noMoreObjects: function(aCaller) { + safeCall(aCallback, null); + } + }); + }, + + /** + * Asynchronously gets all current AddonInstalls optionally limiting to a list + * of types. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * A callback which will be passed an array of AddonInstalls + * @throws If the aCallback argument is not specified + */ + getInstallsByTypes: function(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let installs = []; + + new AsyncObjectCaller(this.providers, "getInstallsByTypes", { + nextObject: function(aCaller, aProvider) { + callProviderAsync(aProvider, "getInstallsByTypes", aTypes, + function(aProviderInstalls) { + if (aProviderInstalls) { + installs = installs.concat(aProviderInstalls); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function(aCaller) { + safeCall(aCallback, installs); + } + }); + }, + + /** + * Asynchronously gets all current AddonInstalls. + * + * @param aCallback + * A callback which will be passed an array of AddonInstalls + */ + getAllInstalls: function(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + this.getInstallsByTypes(null, aCallback); + }, + + /** + * Synchronously map a URI to the corresponding Addon ID. + * + * Mappable URIs are limited to in-application resources belonging to the + * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. + * but do not include URIs from meta data, such as the add-on homepage. + * + * @param aURI + * nsIURI to map to an addon id + * @return string containing the Addon ID or null + * @see amIAddonManager.mapURIToAddonID + */ + mapURIToAddonID: function(aURI) { + if (!(aURI instanceof Ci.nsIURI)) { + throw Components.Exception("aURI is not a nsIURI", + Cr.NS_ERROR_INVALID_ARG); + } + + // Try all providers + let providers = [...this.providers]; + for (let provider of providers) { + var id = callProvider(provider, "mapURIToAddonID", null, aURI); + if (id !== null) { + return id; + } + } + + return null; + }, + + /** + * Checks whether installation is enabled for a particular mimetype. + * + * @param aMimetype + * The mimetype to check + * @return true if installation is enabled for the mimetype + */ + isInstallEnabled: function(aMimetype) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype) && + callProvider(provider, "isInstallEnabled")) + return true; + } + return false; + }, + + /** + * Checks whether a particular source is allowed to install add-ons of a + * given mimetype. + * + * @param aMimetype + * The mimetype of the add-on + * @param aInstallingPrincipal + * The nsIPrincipal that initiated the install + * @return true if the source is allowed to install this mimetype + */ + isInstallAllowed: function(aMimetype, aInstallingPrincipal) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) + throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype) && + callProvider(provider, "isInstallAllowed", null, aInstallingPrincipal)) + return true; + } + return false; + }, + + /** + * Starts installation of an array of AddonInstalls notifying the registered + * web install listener of blocked or started installs. + * + * @param aMimetype + * The mimetype of add-ons being installed + * @param aBrowser + * The optional browser element that started the installs + * @param aInstallingPrincipal + * The nsIPrincipal that initiated the install + * @param aInstalls + * The array of AddonInstalls to be installed + */ + installAddonsFromWebpage: function(aMimetype, aBrowser, + aInstallingPrincipal, aInstalls) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aBrowser && !(aBrowser instanceof Ci.nsIDOMElement)) + throw Components.Exception("aSource must be a nsIDOMElement, or null", + Cr.NS_ERROR_INVALID_ARG); + + if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) + throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", + Cr.NS_ERROR_INVALID_ARG); + + if (!Array.isArray(aInstalls)) + throw Components.Exception("aInstalls must be an array", + Cr.NS_ERROR_INVALID_ARG); + + if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) { + logger.warn("No web installer available, cancelling all installs"); + for (let install of aInstalls) + install.cancel(); + return; + } + + // When a chrome in-content UI has loaded a inside to host a + // website we want to do our security checks on the inner-browser but + // notify front-end that install events came from the outer-browser (the + // main tab's browser). Check this by seeing if the browser we've been + // passed is in a content type docshell and if so get the outer-browser. + let topBrowser = aBrowser; + let docShell = aBrowser.ownerDocument.defaultView + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIDocShellTreeItem); + if (docShell.itemType == Ci.nsIDocShellTreeItem.typeContent) + topBrowser = docShell.chromeEventHandler; + + try { + let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]. + getService(Ci.amIWebInstallListener); + + if (!this.isInstallEnabled(aMimetype)) { + for (let install of aInstalls) + install.cancel(); + + weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length); + return; + } + else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) { + for (let install of aInstalls) + install.cancel(); + + if (weblistener instanceof Ci.amIWebInstallListener2) { + weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length); + } + return; + } + + // The installs may start now depending on the web install listener, + // listen for the browser navigating to a new origin and cancel the + // installs in that case. + new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls); + + if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) { + if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length)) { + for (let install of aInstalls) + install.install(); + } + } + else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length)) { + for (let install of aInstalls) + install.install(); + } + } + catch (e) { + // In the event that the weblistener throws during instantiation or when + // calling onWebInstallBlocked or onWebInstallRequested all of the + // installs should get cancelled. + logger.warn("Failure calling web installer", e); + for (let install of aInstalls) + install.cancel(); + } + }, + + /** + * Adds a new InstallListener if the listener is not already registered. + * + * @param aListener + * The InstallListener to add + */ + addInstallListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a InstallListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.installListeners.some(function(i) { + return i == aListener; })) + this.installListeners.push(aListener); + }, + + /** + * Removes an InstallListener if the listener is registered. + * + * @param aListener + * The InstallListener to remove + */ + removeInstallListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a InstallListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.installListeners.length) { + if (this.installListeners[pos] == aListener) + this.installListeners.splice(pos, 1); + else + pos++; + } + }, + /* + * Adds new or overrides existing UpgradeListener. + * + * @param aInstanceID + * The instance ID of an addon to register a listener for. + * @param aCallback + * The callback to invoke when updates are available for this addon. + * @throws if there is no addon matching the instanceID + */ + addUpgradeListener: function(aInstanceID, aCallback) { + if (!aInstanceID || typeof aInstanceID != "symbol") + throw Components.Exception("aInstanceID must be a symbol", + Cr.NS_ERROR_INVALID_ARG); + + if (!aCallback || typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + this.getAddonByInstanceID(aInstanceID).then(wrapper => { + if (!wrapper) { + throw Error("No addon matching instanceID:", aInstanceID.toString()); + } + let addonId = wrapper.addonId(); + logger.debug(`Registering upgrade listener for ${addonId}`); + this.upgradeListeners.set(addonId, aCallback); + }); + }, + + /** + * Removes an UpgradeListener if the listener is registered. + * + * @param aInstanceID + * The instance ID of the addon to remove + */ + removeUpgradeListener: function(aInstanceID) { + if (!aInstanceID || typeof aInstanceID != "symbol") + throw Components.Exception("aInstanceID must be a symbol", + Cr.NS_ERROR_INVALID_ARG); + + this.getAddonByInstanceID(aInstanceID).then(addon => { + if (!addon) { + throw Error("No addon for instanceID:", aInstanceID.toString()); + } + if (this.upgradeListeners.has(addon.id)) { + this.upgradeListeners.delete(addon.id); + } else { + throw Error("No upgrade listener registered for addon ID:", addon.id); + } + }); + }, + + /** + * Installs a temporary add-on from a local file or directory. + * @param aFile + * An nsIFile for the file or directory of the add-on to be + * temporarily installed. + * @return a Promise that rejects if the add-on is not a valid restartless + * add-on or if the same ID is already temporarily installed. + */ + installTemporaryAddon: function(aFile) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!(aFile instanceof Ci.nsIFile)) + throw Components.Exception("aFile must be a nsIFile", + Cr.NS_ERROR_INVALID_ARG); + + return AddonManagerInternal._getProviderByName("XPIProvider") + .installTemporaryAddon(aFile); + }, + + installAddonFromSources: function(aFile) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!(aFile instanceof Ci.nsIFile)) + throw Components.Exception("aFile must be a nsIFile", + Cr.NS_ERROR_INVALID_ARG); + + return AddonManagerInternal._getProviderByName("XPIProvider") + .installAddonFromSources(aFile); + }, + + /** + * Returns an Addon corresponding to an instance ID. + * @param aInstanceID + * An Addon Instance ID symbol + * @return {Promise} + * @resolves The found Addon or null if no such add-on exists. + * @rejects Never + * @throws if the aInstanceID argument is not specified + * or the AddonManager is not initialized + */ + getAddonByInstanceID: function(aInstanceID) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aInstanceID || typeof aInstanceID != "symbol") + throw Components.Exception("aInstanceID must be a Symbol()", + Cr.NS_ERROR_INVALID_ARG); + + return AddonManagerInternal._getProviderByName("XPIProvider") + .getAddonByInstanceID(aInstanceID); + }, + + /** + * Gets an icon from the icon set provided by the add-on + * that is closest to the specified size. + * + * The optional window parameter will be used to determine + * the screen resolution and select a more appropriate icon. + * Calling this method with 48px on retina screens will try to + * match an icon of size 96px. + * + * @param aAddon + * An addon object, meaning: + * An object with either an icons property that is a key-value + * list of icon size and icon URL, or an object having an iconURL + * and icon64URL property. + * @param aSize + * Ideal icon size in pixels + * @param aWindow + * Optional window object for determining the correct scale. + * @return {String} The absolute URL of the icon or null if the addon doesn't have icons + */ + getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) { + if (aWindow && aWindow.devicePixelRatio) { + aSize *= aWindow.devicePixelRatio; + } + + let icons = aAddon.icons; + + // certain addon-types only have iconURLs + if (!icons) { + icons = {}; + if (aAddon.iconURL) { + icons[32] = aAddon.iconURL; + icons[48] = aAddon.iconURL; + } + if (aAddon.icon64URL) { + icons[64] = aAddon.icon64URL; + } + } + + // quick return if the exact size was found + if (icons[aSize]) { + return icons[aSize]; + } + + let bestSize = null; + + for (let size of Object.keys(icons)) { + if (!INTEGER.test(size)) { + throw Components.Exception("Invalid icon size, must be an integer", + Cr.NS_ERROR_ILLEGAL_VALUE); + } + + size = parseInt(size, 10); + + if (!bestSize) { + bestSize = size; + continue; + } + + if (size > aSize && bestSize > aSize) { + // If both best size and current size are larger than the wanted size then choose + // the one closest to the wanted size + bestSize = Math.min(bestSize, size); + } + else { + // Otherwise choose the largest of the two so we'll prefer sizes as close to below aSize + // or above aSize + bestSize = Math.max(bestSize, size); + } + } + + return icons[bestSize] || null; + }, + + /** + * Asynchronously gets an add-on with a specific ID. + * + * @param aID + * The ID of the add-on to retrieve + * @return {Promise} + * @resolves The found Addon or null if no such add-on exists. + * @rejects Never + * @throws if the aID argument is not specified + */ + getAddonByID: function(aID) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let promises = Array.from(this.providers, + p => promiseCallProvider(p, "getAddonByID", aID)); + return Promise.all(promises).then(aAddons => { + return aAddons.find(a => !!a) || null; + }); + }, + + /** + * Asynchronously get an add-on with a specific Sync GUID. + * + * @param aGUID + * String GUID of add-on to retrieve + * @param aCallback + * The callback to pass the retrieved add-on to. + * @throws if the aGUID or aCallback arguments are not specified + */ + getAddonBySyncGUID: function(aGUID, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aGUID || typeof aGUID != "string") + throw Components.Exception("aGUID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", { + nextObject: function(aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonBySyncGUID", aGUID, + function(aAddon) { + if (aAddon) { + safeCall(aCallback, aAddon); + } else { + aCaller.callNext(); + } + }); + }, + + noMoreObjects: function(aCaller) { + safeCall(aCallback, null); + } + }); + }, + + /** + * Asynchronously gets an array of add-ons. + * + * @param aIDs + * The array of IDs to retrieve + * @return {Promise} + * @resolves The array of found add-ons. + * @rejects Never + * @throws if the aIDs argument is not specified + */ + getAddonsByIDs: function(aIDs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!Array.isArray(aIDs)) + throw Components.Exception("aIDs must be an array", + Cr.NS_ERROR_INVALID_ARG); + + let promises = aIDs.map(a => AddonManagerInternal.getAddonByID(a)); + return Promise.all(promises); + }, + + /** + * Asynchronously gets add-ons of specific types. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * The callback to pass an array of Addons to. + * @throws if the aCallback argument is not specified + */ + getAddonsByTypes: function(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let addons = []; + + new AsyncObjectCaller(this.providers, "getAddonsByTypes", { + nextObject: function(aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonsByTypes", aTypes, + function(aProviderAddons) { + if (aProviderAddons) { + addons = addons.concat(aProviderAddons); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function(aCaller) { + safeCall(aCallback, addons); + } + }); + }, + + /** + * Asynchronously gets all installed add-ons. + * + * @param aCallback + * A callback which will be passed an array of Addons + */ + getAllAddons: function(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + this.getAddonsByTypes(null, aCallback); + }, + + /** + * Asynchronously gets add-ons that have operations waiting for an application + * restart to complete. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * The callback to pass the array of Addons to + * @throws if the aCallback argument is not specified + */ + getAddonsWithOperationsByTypes: function(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let addons = []; + + new AsyncObjectCaller(this.providers, "getAddonsWithOperationsByTypes", { + nextObject: function getAddonsWithOperationsByTypes_nextObject + (aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonsWithOperationsByTypes", aTypes, + function getAddonsWithOperationsByTypes_concatAddons + (aProviderAddons) { + if (aProviderAddons) { + addons = addons.concat(aProviderAddons); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function(caller) { + safeCall(aCallback, addons); + } + }); + }, + + /** + * Adds a new AddonManagerListener if the listener is not already registered. + * + * @param aListener + * The listener to add + */ + addManagerListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonManagerListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.managerListeners.some(i => i == aListener)) + this.managerListeners.push(aListener); + }, + + /** + * Removes an AddonManagerListener if the listener is registered. + * + * @param aListener + * The listener to remove + */ + removeManagerListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonManagerListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.managerListeners.length) { + if (this.managerListeners[pos] == aListener) + this.managerListeners.splice(pos, 1); + else + pos++; + } + }, + + /** + * Adds a new AddonListener if the listener is not already registered. + * + * @param aListener + * The AddonListener to add + */ + addAddonListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.addonListeners.some(i => i == aListener)) + this.addonListeners.push(aListener); + }, + + /** + * Removes an AddonListener if the listener is registered. + * + * @param aListener + * The AddonListener to remove + */ + removeAddonListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.addonListeners.length) { + if (this.addonListeners[pos] == aListener) + this.addonListeners.splice(pos, 1); + else + pos++; + } + }, + + /** + * Adds a new TypeListener if the listener is not already registered. + * + * @param aListener + * The TypeListener to add + */ + addTypeListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a TypeListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.typeListeners.some(i => i == aListener)) + this.typeListeners.push(aListener); + }, + + /** + * Removes an TypeListener if the listener is registered. + * + * @param aListener + * The TypeListener to remove + */ + removeTypeListener: function(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a TypeListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.typeListeners.length) { + if (this.typeListeners[pos] == aListener) + this.typeListeners.splice(pos, 1); + else + pos++; + } + }, + + get addonTypes() { + // A read-only wrapper around the types dictionary + return new Proxy(this.types, { + defineProperty(target, property, descriptor) { + // Not allowed to define properties + return false; + }, + + deleteProperty(target, property) { + // Not allowed to delete properties + return false; + }, + + get(target, property, receiver) { + if (!target.hasOwnProperty(property)) + return undefined; + + return target[property].type; + }, + + getOwnPropertyDescriptor(target, property) { + if (!target.hasOwnProperty(property)) + return undefined; + + return { + value: target[property].type, + writable: false, + // Claim configurability to maintain the proxy invariants. + configurable: true, + enumerable: true + } + }, + + preventExtensions(target) { + // Not allowed to prevent adding new properties + return false; + }, + + set(target, property, value, receiver) { + // Not allowed to set properties + return false; + }, + + setPrototypeOf(target, prototype) { + // Not allowed to change prototype + return false; + } + }); + }, + + get autoUpdateDefault() { + return gAutoUpdateDefault; + }, + + set autoUpdateDefault(aValue) { + aValue = !!aValue; + if (aValue != gAutoUpdateDefault) + Services.prefs.setBoolPref(PREF_EM_AUTOUPDATE_DEFAULT, aValue); + return aValue; + }, + + get checkCompatibility() { + return gCheckCompatibility; + }, + + set checkCompatibility(aValue) { + aValue = !!aValue; + if (aValue != gCheckCompatibility) { + if (!aValue) + Services.prefs.setBoolPref(PREF_EM_CHECK_COMPATIBILITY, false); + else + Services.prefs.clearUserPref(PREF_EM_CHECK_COMPATIBILITY); + } + return aValue; + }, + + get strictCompatibility() { + return gStrictCompatibility; + }, + + set strictCompatibility(aValue) { + aValue = !!aValue; + if (aValue != gStrictCompatibility) + Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, aValue); + return aValue; + }, + + get checkUpdateSecurityDefault() { + return gCheckUpdateSecurityDefault; + }, + + get checkUpdateSecurity() { + return gCheckUpdateSecurity; + }, + + set checkUpdateSecurity(aValue) { + aValue = !!aValue; + if (aValue != gCheckUpdateSecurity) { + if (aValue != gCheckUpdateSecurityDefault) + Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, aValue); + else + Services.prefs.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY); + } + return aValue; + }, + + get updateEnabled() { + return gUpdateEnabled; + }, + + set updateEnabled(aValue) { + aValue = !!aValue; + if (aValue != gUpdateEnabled) + Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue); + return aValue; + }, + + get hotfixID() { + return gHotfixID; + }, + + webAPI: { + // installs maps integer ids to AddonInstall instances. + installs: new Map(), + nextInstall: 0, + + sendEvent: null, + setEventHandler(fn) { + this.sendEvent = fn; + }, + + getAddonByID(target, id) { + return new Promise(resolve => { + AddonManager.getAddonByID(id, (addon) => { + resolve(webAPIForAddon(addon)); + }); + }); + }, + + // helper to copy (and convert) the properties we care about + copyProps(install, obj) { + obj.state = AddonManager.stateToString(install.state); + obj.error = AddonManager.errorToString(install.error); + obj.progress = install.progress; + obj.maxProgress = install.maxProgress; + }, + + makeListener(id, mm) { + const events = [ + "onDownloadStarted", + "onDownloadProgress", + "onDownloadEnded", + "onDownloadCancelled", + "onDownloadFailed", + "onInstallStarted", + "onInstallEnded", + "onInstallCancelled", + "onInstallFailed", + ]; + + let listener = {}; + events.forEach(event => { + listener[event] = (install) => { + let data = {event, id}; + AddonManager.webAPI.copyProps(install, data); + this.sendEvent(mm, data); + } + }); + return listener; + }, + + forgetInstall(id) { + let info = this.installs.get(id); + if (!info) { + throw new Error(`forgetInstall cannot find ${id}`); + } + info.install.removeListener(info.listener); + this.installs.delete(id); + }, + + createInstall(target, options) { + // Throw an appropriate error if the given URL is not valid + // as an installation source. Return silently if it is okay. + function checkInstallUrl(url) { + let host = Services.io.newURI(options.url, null, null).host; + if (WEBAPI_INSTALL_HOSTS.includes(host)) { + return; + } + if (Services.prefs.getBoolPref(PREF_WEBAPI_TESTING) + && WEBAPI_TEST_INSTALL_HOSTS.includes(host)) { + return; + } + + throw new Error(`Install from ${host} not permitted`); + } + + return new Promise((resolve, reject) => { + try { + checkInstallUrl(options.url); + } catch (err) { + reject({message: err.message}); + return; + } + + let newInstall = install => { + let id = this.nextInstall++; + let listener = this.makeListener(id, target.messageManager); + install.addListener(listener); + + this.installs.set(id, {install, target, listener}); + + let result = {id}; + this.copyProps(install, result); + resolve(result); + }; + AddonManager.getInstallForURL(options.url, newInstall, "application/x-xpinstall", options.hash); + }); + }, + + addonUninstall(target, id) { + return new Promise(resolve => { + AddonManager.getAddonByID(id, addon => { + if (!addon) { + resolve(false); + } + + try { + addon.uninstall(); + resolve(true); + } catch (err) { + Cu.reportError(err); + resolve(false); + } + }); + }); + }, + + addonSetEnabled(target, id, value) { + return new Promise((resolve, reject) => { + AddonManager.getAddonByID(id, addon => { + if (!addon) { + reject({message: `No such addon ${id}`}); + } + addon.userDisabled = !value; + resolve(); + }); + }); + }, + + addonInstallDoInstall(target, id) { + let state = this.installs.get(id); + if (!state) { + return Promise.reject(`invalid id ${id}`); + } + return Promise.resolve(state.install.install()); + }, + + addonInstallCancel(target, id) { + let state = this.installs.get(id); + if (!state) { + return Promise.reject(`invalid id ${id}`); + } + return Promise.resolve(state.install.cancel()); + }, + + clearInstalls(ids) { + for (let id of ids) { + this.forgetInstall(id); + } + }, + + clearInstallsFrom(mm) { + for (let [id, info] of this.installs) { + if (info.target.messageManager == mm) { + this.forgetInstall(id); + } + } + }, + }, +}; + +/** + * Should not be used outside of core Mozilla code. This is a private API for + * the startup and platform integration code to use. Refer to the methods on + * AddonManagerInternal for documentation however note that these methods are + * subject to change at any time. + */ +this.AddonManagerPrivate = { + startup: function() { + AddonManagerInternal.startup(); + }, + + registerProvider: function(aProvider, aTypes) { + AddonManagerInternal.registerProvider(aProvider, aTypes); + }, + + unregisterProvider: function(aProvider) { + AddonManagerInternal.unregisterProvider(aProvider); + }, + + markProviderSafe: function(aProvider) { + AddonManagerInternal.markProviderSafe(aProvider); + }, + + backgroundUpdateCheck: function() { + return AddonManagerInternal.backgroundUpdateCheck(); + }, + + backgroundUpdateTimerHandler() { + // Don't call through to the real update check if no checks are enabled. + let checkHotfix = AddonManagerInternal.hotfixID && + Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && + Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); + + if (!AddonManagerInternal.updateEnabled && !checkHotfix) { + logger.info("Skipping background update check"); + return; + } + // Don't return the promise here, since the caller doesn't care. + AddonManagerInternal.backgroundUpdateCheck(); + }, + + addStartupChange: function(aType, aID) { + AddonManagerInternal.addStartupChange(aType, aID); + }, + + removeStartupChange: function(aType, aID) { + AddonManagerInternal.removeStartupChange(aType, aID); + }, + + notifyAddonChanged: function(aID, aType, aPendingRestart) { + AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart); + }, + + updateAddonAppDisabledStates: function() { + AddonManagerInternal.updateAddonAppDisabledStates(); + }, + + updateAddonRepositoryData: function(aCallback) { + AddonManagerInternal.updateAddonRepositoryData(aCallback); + }, + + callInstallListeners: function(...aArgs) { + return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal, + aArgs); + }, + + callAddonListeners: function(...aArgs) { + AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs); + }, + + AddonAuthor: AddonAuthor, + + AddonScreenshot: AddonScreenshot, + + AddonCompatibilityOverride: AddonCompatibilityOverride, + + AddonType: AddonType, + + recordTimestamp: function(name, value) { + AddonManagerInternal.recordTimestamp(name, value); + }, + + _simpleMeasures: {}, + recordSimpleMeasure: function(name, value) { + this._simpleMeasures[name] = value; + }, + + recordException: function(aModule, aContext, aException) { + let report = { + module: aModule, + context: aContext + }; + + if (typeof aException == "number") { + report.message = Components.Exception("", aException).name; + } + else { + report.message = aException.toString(); + if (aException.fileName) { + report.file = aException.fileName; + report.line = aException.lineNumber; + } + } + + this._simpleMeasures.exception = report; + }, + + getSimpleMeasures: function() { + return this._simpleMeasures; + }, + + getTelemetryDetails: function() { + return AddonManagerInternal.telemetryDetails; + }, + + setTelemetryDetails: function(aProvider, aDetails) { + AddonManagerInternal.telemetryDetails[aProvider] = aDetails; + }, + + // Start a timer, record a simple measure of the time interval when + // timer.done() is called + simpleTimer: function(aName) { + let startTime = Cu.now(); + return { + done: () => this.recordSimpleMeasure(aName, Math.round(Cu.now() - startTime)) + }; + }, + + /** + * Helper to call update listeners when no update is available. + * + * This can be used as an implementation for Addon.findUpdates() when + * no update mechanism is available. + */ + callNoUpdateListeners: function(addon, listener, reason, appVersion, platformVersion) { + if ("onNoCompatibilityUpdateAvailable" in listener) { + safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon); + } + if ("onNoUpdateAvailable" in listener) { + safeCall(listener.onNoUpdateAvailable.bind(listener), addon); + } + if ("onUpdateFinished" in listener) { + safeCall(listener.onUpdateFinished.bind(listener), addon); + } + }, + + get webExtensionsMinPlatformVersion() { + return gWebExtensionsMinPlatformVersion; + }, + + hasUpgradeListener: function(aId) { + return AddonManagerInternal.upgradeListeners.has(aId); + }, + + getUpgradeListener: function(aId) { + return AddonManagerInternal.upgradeListeners.get(aId); + }, +}; + +/** + * This is the public API that UI and developers should be calling. All methods + * just forward to AddonManagerInternal. + */ +this.AddonManager = { + // Constants for the AddonInstall.state property + // These will show up as AddonManager.STATE_* (eg, STATE_AVAILABLE) + _states: new Map([ + // The install is available for download. + ["STATE_AVAILABLE", 0], + // The install is being downloaded. + ["STATE_DOWNLOADING", 1], + // The install is checking for compatibility information. + ["STATE_CHECKING", 2], + // The install is downloaded and ready to install. + ["STATE_DOWNLOADED", 3], + // The download failed. + ["STATE_DOWNLOAD_FAILED", 4], + // The install has been postponed. + ["STATE_POSTPONED", 5], + // The add-on is being installed. + ["STATE_INSTALLING", 6], + // The add-on has been installed. + ["STATE_INSTALLED", 7], + // The install failed. + ["STATE_INSTALL_FAILED", 8], + // The install has been cancelled. + ["STATE_CANCELLED", 9], + ]), + + // Constants representing different types of errors while downloading an + // add-on. + // These will show up as AddonManager.ERROR_* (eg, ERROR_NETWORK_FAILURE) + _errors: new Map([ + // The download failed due to network problems. + ["ERROR_NETWORK_FAILURE", -1], + // The downloaded file did not match the provided hash. + ["ERROR_INCORRECT_HASH", -2], + // The downloaded file seems to be corrupted in some way. + ["ERROR_CORRUPT_FILE", -3], + // An error occured trying to write to the filesystem. + ["ERROR_FILE_ACCESS", -4], + // The add-on must be signed and isn't. + ["ERROR_SIGNEDSTATE_REQUIRED", -5], + // The downloaded add-on had a different type than expected. + ["ERROR_UNEXPECTED_ADDON_TYPE", -6], + // The addon did not have the expected ID + ["ERROR_INCORRECT_ID", -7], + ]), + + // These must be kept in sync with AddonUpdateChecker. + // No error was encountered. + UPDATE_STATUS_NO_ERROR: 0, + // The update check timed out + UPDATE_STATUS_TIMEOUT: -1, + // There was an error while downloading the update information. + UPDATE_STATUS_DOWNLOAD_ERROR: -2, + // The update information was malformed in some way. + UPDATE_STATUS_PARSE_ERROR: -3, + // The update information was not in any known format. + UPDATE_STATUS_UNKNOWN_FORMAT: -4, + // The update information was not correctly signed or there was an SSL error. + UPDATE_STATUS_SECURITY_ERROR: -5, + // The update was cancelled. + UPDATE_STATUS_CANCELLED: -6, + + // Constants to indicate why an update check is being performed + // Update check has been requested by the user. + UPDATE_WHEN_USER_REQUESTED: 1, + // Update check is necessary to see if the Addon is compatibile with a new + // version of the application. + UPDATE_WHEN_NEW_APP_DETECTED: 2, + // Update check is necessary because a new application has been installed. + UPDATE_WHEN_NEW_APP_INSTALLED: 3, + // Update check is a regular background update check. + UPDATE_WHEN_PERIODIC_UPDATE: 16, + // Update check is needed to check an Addon that is being installed. + UPDATE_WHEN_ADDON_INSTALLED: 17, + + // Constants for operations in Addon.pendingOperations + // Indicates that the Addon has no pending operations. + PENDING_NONE: 0, + // Indicates that the Addon will be enabled after the application restarts. + PENDING_ENABLE: 1, + // Indicates that the Addon will be disabled after the application restarts. + PENDING_DISABLE: 2, + // Indicates that the Addon will be uninstalled after the application restarts. + PENDING_UNINSTALL: 4, + // Indicates that the Addon will be installed after the application restarts. + PENDING_INSTALL: 8, + PENDING_UPGRADE: 16, + + // Constants for operations in Addon.operationsRequiringRestart + // Indicates that restart isn't required for any operation. + OP_NEEDS_RESTART_NONE: 0, + // Indicates that restart is required for enabling the addon. + OP_NEEDS_RESTART_ENABLE: 1, + // Indicates that restart is required for disabling the addon. + OP_NEEDS_RESTART_DISABLE: 2, + // Indicates that restart is required for uninstalling the addon. + OP_NEEDS_RESTART_UNINSTALL: 4, + // Indicates that restart is required for installing the addon. + OP_NEEDS_RESTART_INSTALL: 8, + + // Constants for permissions in Addon.permissions. + // Indicates that the Addon can be uninstalled. + PERM_CAN_UNINSTALL: 1, + // Indicates that the Addon can be enabled by the user. + PERM_CAN_ENABLE: 2, + // Indicates that the Addon can be disabled by the user. + PERM_CAN_DISABLE: 4, + // Indicates that the Addon can be upgraded. + PERM_CAN_UPGRADE: 8, + // Indicates that the Addon can be set to be optionally enabled + // on a case-by-case basis. + PERM_CAN_ASK_TO_ACTIVATE: 16, + + // General descriptions of where items are installed. + // Installed in this profile. + SCOPE_PROFILE: 1, + // Installed for all of this user's profiles. + SCOPE_USER: 2, + // Installed and owned by the application. + SCOPE_APPLICATION: 4, + // Installed for all users of the computer. + SCOPE_SYSTEM: 8, + // Installed temporarily + SCOPE_TEMPORARY: 16, + // The combination of all scopes. + SCOPE_ALL: 31, + + // Add-on type is expected to be displayed in the UI in a list. + VIEW_TYPE_LIST: "list", + + // Constants describing how add-on types behave. + + // If no add-ons of a type are installed, then the category for that add-on + // type should be hidden in the UI. + TYPE_UI_HIDE_EMPTY: 16, + // Indicates that this add-on type supports the ask-to-activate state. + // That is, add-ons of this type can be set to be optionally enabled + // on a case-by-case basis. + TYPE_SUPPORTS_ASK_TO_ACTIVATE: 32, + // The add-on type natively supports undo for restartless uninstalls. + // If this flag is not specified, the UI is expected to handle this via + // disabling the add-on, and performing the actual uninstall at a later time. + TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL: 64, + + // Constants for Addon.applyBackgroundUpdates. + // Indicates that the Addon should not update automatically. + AUTOUPDATE_DISABLE: 0, + // Indicates that the Addon should update automatically only if + // that's the global default. + AUTOUPDATE_DEFAULT: 1, + // Indicates that the Addon should update automatically. + AUTOUPDATE_ENABLE: 2, + + // Constants for how Addon options should be shown. + // Options will be opened in a new window + OPTIONS_TYPE_DIALOG: 1, + // Options will be displayed within the AM detail view + OPTIONS_TYPE_INLINE: 2, + // Options will be displayed in a new tab, if possible + OPTIONS_TYPE_TAB: 3, + // Same as OPTIONS_TYPE_INLINE, but no Preferences button will be shown. + // Used to indicate that only non-interactive information will be shown. + OPTIONS_TYPE_INLINE_INFO: 4, + // Similar to OPTIONS_TYPE_INLINE, but rather than generating inline + // options from a specially-formatted XUL file, the contents of the + // file are simply displayed in an inline element. + OPTIONS_TYPE_INLINE_BROWSER: 5, + + // Constants for displayed or hidden options notifications + // Options notification will be displayed + OPTIONS_NOTIFICATION_DISPLAYED: "addon-options-displayed", + // Options notification will be hidden + OPTIONS_NOTIFICATION_HIDDEN: "addon-options-hidden", + + // Constants for getStartupChanges, addStartupChange and removeStartupChange + // Add-ons that were detected as installed during startup. Doesn't include + // add-ons that were pending installation the last time the application ran. + STARTUP_CHANGE_INSTALLED: "installed", + // Add-ons that were detected as changed during startup. This includes an + // add-on moving to a different location, changing version or just having + // been detected as possibly changed. + STARTUP_CHANGE_CHANGED: "changed", + // Add-ons that were detected as uninstalled during startup. Doesn't include + // add-ons that were pending uninstallation the last time the application ran. + STARTUP_CHANGE_UNINSTALLED: "uninstalled", + // Add-ons that were detected as disabled during startup, normally because of + // an application change making an add-on incompatible. Doesn't include + // add-ons that were pending being disabled the last time the application ran. + STARTUP_CHANGE_DISABLED: "disabled", + // Add-ons that were detected as enabled during startup, normally because of + // an application change making an add-on compatible. Doesn't include + // add-ons that were pending being enabled the last time the application ran. + STARTUP_CHANGE_ENABLED: "enabled", + + // Constants for Addon.signedState. Any states that should cause an add-on + // to be unusable in builds that require signing should have negative values. + // Add-on signing is not required, e.g. because the pref is disabled. + SIGNEDSTATE_NOT_REQUIRED: undefined, + // Add-on is signed but signature verification has failed. + SIGNEDSTATE_BROKEN: -2, + // Add-on may be signed but by an certificate that doesn't chain to our + // our trusted certificate. + SIGNEDSTATE_UNKNOWN: -1, + // Add-on is unsigned. + SIGNEDSTATE_MISSING: 0, + // Add-on is preliminarily reviewed. + SIGNEDSTATE_PRELIMINARY: 1, + // Add-on is fully reviewed. + SIGNEDSTATE_SIGNED: 2, + // Add-on is system add-on. + SIGNEDSTATE_SYSTEM: 3, + + // Constants for the Addon.userDisabled property + // Indicates that the userDisabled state of this add-on is currently + // ask-to-activate. That is, it can be conditionally enabled on a + // case-by-case basis. + STATE_ASK_TO_ACTIVATE: "askToActivate", + + get __AddonManagerInternal__() { + return AppConstants.DEBUG ? AddonManagerInternal : undefined; + }, + + get isReady() { + return gStartupComplete && !gShutdownInProgress; + }, + + init() { + this._stateToString = new Map(); + for (let [name, value] of this._states) { + this[name] = value; + this._stateToString.set(value, name); + } + this._errorToString = new Map(); + for (let [name, value] of this._errors) { + this[name] = value; + this._errorToString.set(value, name); + } + }, + + stateToString(state) { + return this._stateToString.get(state); + }, + + errorToString(err) { + return err ? this._errorToString.get(err) : null; + }, + + getInstallForURL: function(aUrl, aCallback, aMimetype, + aHash, aName, aIcons, + aVersion, aBrowser) { + AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash, + aName, aIcons, aVersion, aBrowser); + }, + + getInstallForFile: function(aFile, aCallback, aMimetype) { + AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype); + }, + + /** + * Gets an array of add-on IDs that changed during the most recent startup. + * + * @param aType + * The type of startup change to get + * @return An array of add-on IDs + */ + getStartupChanges: function(aType) { + if (!(aType in AddonManagerInternal.startupChanges)) + return []; + return AddonManagerInternal.startupChanges[aType].slice(0); + }, + + getAddonByID: function(aID, aCallback) { + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + AddonManagerInternal.getAddonByID(aID) + .then(makeSafe(aCallback)) + .catch(logger.error); + }, + + getAddonBySyncGUID: function(aGUID, aCallback) { + AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback); + }, + + getAddonsByIDs: function(aIDs, aCallback) { + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + AddonManagerInternal.getAddonsByIDs(aIDs) + .then(makeSafe(aCallback)) + .catch(logger.error); + }, + + getAddonsWithOperationsByTypes: function(aTypes, aCallback) { + AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes, aCallback); + }, + + getAddonsByTypes: function(aTypes, aCallback) { + AddonManagerInternal.getAddonsByTypes(aTypes, aCallback); + }, + + getAllAddons: function(aCallback) { + AddonManagerInternal.getAllAddons(aCallback); + }, + + getInstallsByTypes: function(aTypes, aCallback) { + AddonManagerInternal.getInstallsByTypes(aTypes, aCallback); + }, + + getAllInstalls: function(aCallback) { + AddonManagerInternal.getAllInstalls(aCallback); + }, + + mapURIToAddonID: function(aURI) { + return AddonManagerInternal.mapURIToAddonID(aURI); + }, + + isInstallEnabled: function(aType) { + return AddonManagerInternal.isInstallEnabled(aType); + }, + + isInstallAllowed: function(aType, aInstallingPrincipal) { + return AddonManagerInternal.isInstallAllowed(aType, aInstallingPrincipal); + }, + + installAddonsFromWebpage: function(aType, aBrowser, aInstallingPrincipal, + aInstalls) { + AddonManagerInternal.installAddonsFromWebpage(aType, aBrowser, + aInstallingPrincipal, + aInstalls); + }, + + installTemporaryAddon: function(aDirectory) { + return AddonManagerInternal.installTemporaryAddon(aDirectory); + }, + + installAddonFromSources: function(aDirectory) { + return AddonManagerInternal.installAddonFromSources(aDirectory); + }, + + getAddonByInstanceID: function(aInstanceID) { + return AddonManagerInternal.getAddonByInstanceID(aInstanceID); + }, + + addManagerListener: function(aListener) { + AddonManagerInternal.addManagerListener(aListener); + }, + + removeManagerListener: function(aListener) { + AddonManagerInternal.removeManagerListener(aListener); + }, + + addInstallListener: function(aListener) { + AddonManagerInternal.addInstallListener(aListener); + }, + + removeInstallListener: function(aListener) { + AddonManagerInternal.removeInstallListener(aListener); + }, + + getUpgradeListener: function(aId) { + return AddonManagerInternal.upgradeListeners.get(aId); + }, + + addUpgradeListener: function(aInstanceID, aCallback) { + AddonManagerInternal.addUpgradeListener(aInstanceID, aCallback); + }, + + removeUpgradeListener: function(aInstanceID) { + AddonManagerInternal.removeUpgradeListener(aInstanceID); + }, + + addAddonListener: function(aListener) { + AddonManagerInternal.addAddonListener(aListener); + }, + + removeAddonListener: function(aListener) { + AddonManagerInternal.removeAddonListener(aListener); + }, + + addTypeListener: function(aListener) { + AddonManagerInternal.addTypeListener(aListener); + }, + + removeTypeListener: function(aListener) { + AddonManagerInternal.removeTypeListener(aListener); + }, + + get addonTypes() { + return AddonManagerInternal.addonTypes; + }, + + /** + * Determines whether an Addon should auto-update or not. + * + * @param aAddon + * The Addon representing the add-on + * @return true if the addon should auto-update, false otherwise. + */ + shouldAutoUpdate: function(aAddon) { + if (!aAddon || typeof aAddon != "object") + throw Components.Exception("aAddon must be specified", + Cr.NS_ERROR_INVALID_ARG); + + if (!("applyBackgroundUpdates" in aAddon)) + return false; + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE) + return true; + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE) + return false; + return this.autoUpdateDefault; + }, + + get checkCompatibility() { + return AddonManagerInternal.checkCompatibility; + }, + + set checkCompatibility(aValue) { + AddonManagerInternal.checkCompatibility = aValue; + }, + + get strictCompatibility() { + return AddonManagerInternal.strictCompatibility; + }, + + set strictCompatibility(aValue) { + AddonManagerInternal.strictCompatibility = aValue; + }, + + get checkUpdateSecurityDefault() { + return AddonManagerInternal.checkUpdateSecurityDefault; + }, + + get checkUpdateSecurity() { + return AddonManagerInternal.checkUpdateSecurity; + }, + + set checkUpdateSecurity(aValue) { + AddonManagerInternal.checkUpdateSecurity = aValue; + }, + + get updateEnabled() { + return AddonManagerInternal.updateEnabled; + }, + + set updateEnabled(aValue) { + AddonManagerInternal.updateEnabled = aValue; + }, + + get autoUpdateDefault() { + return AddonManagerInternal.autoUpdateDefault; + }, + + set autoUpdateDefault(aValue) { + AddonManagerInternal.autoUpdateDefault = aValue; + }, + + get hotfixID() { + return AddonManagerInternal.hotfixID; + }, + + escapeAddonURI: function(aAddon, aUri, aAppVersion) { + return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion); + }, + + getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) { + return AddonManagerInternal.getPreferredIconURL(aAddon, aSize, aWindow); + }, + + get webAPI() { + return AddonManagerInternal.webAPI; + }, + + get shutdown() { + return gShutdownBarrier.client; + }, +}; + +this.AddonManager.init(); + +// load the timestamps module into AddonManagerInternal +Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", AddonManagerInternal); +Object.freeze(AddonManagerInternal); +Object.freeze(AddonManagerPrivate); +Object.freeze(AddonManager); diff --git a/toolkit/mozapps/webextensions/AddonManagerWebAPI.cpp b/toolkit/mozapps/webextensions/AddonManagerWebAPI.cpp new file mode 100644 index 000000000..3f2a7a529 --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonManagerWebAPI.cpp @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AddonManagerWebAPI.h" + +#include "mozilla/dom/Navigator.h" +#include "mozilla/dom/NavigatorBinding.h" + +#include "mozilla/Preferences.h" +#include "nsGlobalWindow.h" + +#include "nsIDocShell.h" +#include "nsIScriptObjectPrincipal.h" + +namespace mozilla { +using namespace mozilla::dom; + +static bool +IsValidHost(const nsACString& host) { + // This is ugly, but Preferences.h doesn't have support + // for default prefs or locked prefs + nsCOMPtr prefService (do_GetService(NS_PREFSERVICE_CONTRACTID)); + nsCOMPtr prefs; + if (prefService) { + prefService->GetDefaultBranch(nullptr, getter_AddRefs(prefs)); + bool isEnabled; + if (NS_SUCCEEDED(prefs->GetBoolPref("xpinstall.enabled", &isEnabled)) && !isEnabled) { + bool isLocked; + prefs->PrefIsLocked("xpinstall.enabled", &isLocked); + if (isLocked) { + return false; + } + } + } + + if (host.Equals("addons.mozilla.org") || + host.Equals("discovery.addons.mozilla.org") || + host.Equals("testpilot.firefox.com")) { + return true; + } + + // When testing allow access to the developer sites. + if (Preferences::GetBool("extensions.webapi.testing", false)) { + if (host.LowerCaseEqualsLiteral("addons.allizom.org") || + host.LowerCaseEqualsLiteral("discovery.addons.allizom.org") || + host.LowerCaseEqualsLiteral("addons-dev.allizom.org") || + host.LowerCaseEqualsLiteral("discovery.addons-dev.allizom.org") || + host.LowerCaseEqualsLiteral("testpilot.stage.mozaws.net") || + host.LowerCaseEqualsLiteral("testpilot.dev.mozaws.net") || + host.LowerCaseEqualsLiteral("example.com")) { + return true; + } + } + + return false; +} + +// Checks if the given uri is secure and matches one of the hosts allowed to +// access the API. +bool +AddonManagerWebAPI::IsValidSite(nsIURI* uri) +{ + if (!uri) { + return false; + } + + bool isSecure; + nsresult rv = uri->SchemeIs("https", &isSecure); + if (NS_FAILED(rv) || !isSecure) { + return false; + } + + nsAutoCString host; + rv = uri->GetHost(host); + if (NS_FAILED(rv)) { + return false; + } + + return IsValidHost(host); +} + +bool +AddonManagerWebAPI::IsAPIEnabled(JSContext* cx, JSObject* obj) +{ + nsGlobalWindow* global = xpc::WindowGlobalOrNull(obj); + if (!global) { + return false; + } + + nsCOMPtr win = global->AsInner(); + if (!win) { + return false; + } + + // Check that the current window and all parent frames are allowed access to + // the API. + while (win) { + nsCOMPtr sop = do_QueryInterface(win); + if (!sop) { + return false; + } + + nsCOMPtr principal = sop->GetPrincipal(); + if (!principal) { + return false; + } + + // Reaching a window with a system principal means we have reached + // privileged UI of some kind so stop at this point and allow access. + if (principal->GetIsSystemPrincipal()) { + return true; + } + + nsCOMPtr docShell = win->GetDocShell(); + if (!docShell) { + // This window has been torn down so don't allow access to the API. + return false; + } + + if (!IsValidSite(win->GetDocumentURI())) { + return false; + } + + // Checks whether there is a parent frame of the same type. This won't cross + // mozbrowser or chrome boundaries. + nsCOMPtr parent; + nsresult rv = docShell->GetSameTypeParent(getter_AddRefs(parent)); + if (NS_FAILED(rv)) { + return false; + } + + if (!parent) { + // No parent means we've hit a mozbrowser or chrome boundary so allow + // access to the API. + return true; + } + + nsIDocument* doc = win->GetDoc(); + if (!doc) { + return false; + } + + doc = doc->GetParentDocument(); + if (!doc) { + // Getting here means something has been torn down so fail safe. + return false; + } + + + win = doc->GetInnerWindow(); + } + + // Found a document with no inner window, don't grant access to the API. + return false; +} + +namespace dom { + +bool +AddonManagerPermissions::IsHostPermitted(const GlobalObject& /*unused*/, const nsAString& host) +{ + return IsValidHost(NS_ConvertUTF16toUTF8(host)); +} + +} // namespace mozilla::dom + + +} // namespace mozilla diff --git a/toolkit/mozapps/webextensions/AddonManagerWebAPI.h b/toolkit/mozapps/webextensions/AddonManagerWebAPI.h new file mode 100644 index 000000000..6830bc91f --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonManagerWebAPI.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef addonmanagerwebapi_h_ +#define addonmanagerwebapi_h_ + +#include "nsPIDOMWindow.h" + +namespace mozilla { + +class AddonManagerWebAPI { +public: + static bool IsAPIEnabled(JSContext* cx, JSObject* obj); + +private: + static bool IsValidSite(nsIURI* uri); +}; + +namespace dom { + +class AddonManagerPermissions { +public: + static bool IsHostPermitted(const GlobalObject&, const nsAString& host); +}; + +} // namespace mozilla::dom + +} // namespace mozilla + +#endif // addonmanagerwebapi_h_ diff --git a/toolkit/mozapps/webextensions/AddonPathService.cpp b/toolkit/mozapps/webextensions/AddonPathService.cpp new file mode 100644 index 000000000..8a405c0ea --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonPathService.cpp @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AddonPathService.h" + +#include "amIAddonManager.h" +#include "nsIURI.h" +#include "nsXULAppAPI.h" +#include "jsapi.h" +#include "nsServiceManagerUtils.h" +#include "nsLiteralString.h" +#include "nsThreadUtils.h" +#include "nsIIOService.h" +#include "nsNetUtil.h" +#include "nsIAddonPolicyService.h" +#include "nsIFileURL.h" +#include "nsIResProtocolHandler.h" +#include "nsIChromeRegistry.h" +#include "nsIJARURI.h" +#include "nsJSUtils.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/ToJSValue.h" +#include "mozilla/AddonPathService.h" +#include "mozilla/Omnijar.h" + +#include + +namespace mozilla { + +struct PathEntryComparator +{ + typedef AddonPathService::PathEntry PathEntry; + + bool Equals(const PathEntry& entry1, const PathEntry& entry2) const + { + return entry1.mPath == entry2.mPath; + } + + bool LessThan(const PathEntry& entry1, const PathEntry& entry2) const + { + return entry1.mPath < entry2.mPath; + } +}; + +AddonPathService::AddonPathService() +{ +} + +AddonPathService::~AddonPathService() +{ + sInstance = nullptr; +} + +NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService) + +AddonPathService *AddonPathService::sInstance; + +/* static */ AddonPathService* +AddonPathService::GetInstance() +{ + if (!sInstance) { + sInstance = new AddonPathService(); + } + NS_ADDREF(sInstance); + return sInstance; +} + +static JSAddonId* +ConvertAddonId(const nsAString& addonIdString) +{ + AutoSafeJSContext cx; + JS::RootedValue strv(cx); + if (!mozilla::dom::ToJSValue(cx, addonIdString, &strv)) { + return nullptr; + } + JS::RootedString str(cx, strv.toString()); + return JS::NewAddonId(cx, str); +} + +JSAddonId* +AddonPathService::Find(const nsAString& path) +{ + // Use binary search to find the nearest entry that is <= |path|. + PathEntryComparator comparator; + unsigned index = mPaths.IndexOfFirstElementGt(PathEntry(path, nullptr), comparator); + if (index == 0) { + return nullptr; + } + const PathEntry& entry = mPaths[index - 1]; + + // Return the entry's addon if its path is a prefix of |path|. + if (StringBeginsWith(path, entry.mPath)) { + return entry.mAddonId; + } + return nullptr; +} + +NS_IMETHODIMP +AddonPathService::FindAddonId(const nsAString& path, nsAString& addonIdString) +{ + if (JSAddonId* id = Find(path)) { + JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id)); + AssignJSFlatString(addonIdString, flat); + } + return NS_OK; +} + +/* static */ JSAddonId* +AddonPathService::FindAddonId(const nsAString& path) +{ + // If no service has been created, then we're not going to find anything. + if (!sInstance) { + return nullptr; + } + + return sInstance->Find(path); +} + +NS_IMETHODIMP +AddonPathService::InsertPath(const nsAString& path, const nsAString& addonIdString) +{ + JSAddonId* addonId = ConvertAddonId(addonIdString); + + // Add the new path in sorted order. + PathEntryComparator comparator; + mPaths.InsertElementSorted(PathEntry(path, addonId), comparator); + return NS_OK; +} + +NS_IMETHODIMP +AddonPathService::MapURIToAddonId(nsIURI* aURI, nsAString& addonIdString) +{ + if (JSAddonId* id = MapURIToAddonID(aURI)) { + JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id)); + AssignJSFlatString(addonIdString, flat); + } + return NS_OK; +} + +static nsresult +ResolveURI(nsIURI* aURI, nsAString& out) +{ + bool equals; + nsresult rv; + nsCOMPtr uri; + nsAutoCString spec; + + // Resolve resource:// URIs. At the end of this if/else block, we + // have both spec and uri variables identifying the same URI. + if (NS_SUCCEEDED(aURI->SchemeIs("resource", &equals)) && equals) { + nsCOMPtr ioService = do_GetIOService(&rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr ph; + rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr irph(do_QueryInterface(ph, &rv)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + rv = irph->ResolveURI(aURI, spec); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + rv = ioService->NewURI(spec, nullptr, nullptr, getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + } else if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &equals)) && equals) { + nsCOMPtr chromeReg = + mozilla::services::GetChromeRegistryService(); + if (NS_WARN_IF(!chromeReg)) + return NS_ERROR_UNEXPECTED; + + rv = chromeReg->ConvertChromeURL(aURI, getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + } else { + uri = aURI; + } + + if (NS_SUCCEEDED(uri->SchemeIs("jar", &equals)) && equals) { + nsCOMPtr jarURI = do_QueryInterface(uri, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr jarFileURI; + rv = jarURI->GetJARFile(getter_AddRefs(jarFileURI)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + return ResolveURI(jarFileURI, out); + } + + if (NS_SUCCEEDED(uri->SchemeIs("file", &equals)) && equals) { + nsCOMPtr baseFileURL = do_QueryInterface(uri, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr file; + rv = baseFileURL->GetFile(getter_AddRefs(file)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + return file->GetPath(out); + } + return NS_ERROR_FAILURE; +} + +JSAddonId* +MapURIToAddonID(nsIURI* aURI) +{ + if (!NS_IsMainThread() || !XRE_IsParentProcess()) { + return nullptr; + } + + bool equals; + nsresult rv; + if (NS_SUCCEEDED(aURI->SchemeIs("moz-extension", &equals)) && equals) { + nsCOMPtr service = do_GetService("@mozilla.org/addons/policy-service;1"); + if (service) { + nsString addonId; + rv = service->ExtensionURIToAddonId(aURI, addonId); + if (NS_FAILED(rv)) + return nullptr; + + return ConvertAddonId(addonId); + } + } + + nsAutoString filePath; + rv = ResolveURI(aURI, filePath); + if (NS_FAILED(rv)) + return nullptr; + + nsCOMPtr greJar = Omnijar::GetPath(Omnijar::GRE); + nsCOMPtr appJar = Omnijar::GetPath(Omnijar::APP); + if (greJar && appJar) { + nsAutoString greJarString, appJarString; + if (NS_FAILED(greJar->GetPath(greJarString)) || NS_FAILED(appJar->GetPath(appJarString))) + return nullptr; + + // If |aURI| is part of either Omnijar, then it can't be part of an + // add-on. This catches pretty much all URLs for Firefox content. + if (filePath.Equals(greJarString) || filePath.Equals(appJarString)) + return nullptr; + } + + // If it's not part of Firefox, we resort to binary searching through the + // add-on paths. + return AddonPathService::FindAddonId(filePath); +} + +} // namespace mozilla diff --git a/toolkit/mozapps/webextensions/AddonPathService.h b/toolkit/mozapps/webextensions/AddonPathService.h new file mode 100644 index 000000000..f739b018f --- /dev/null +++ b/toolkit/mozapps/webextensions/AddonPathService.h @@ -0,0 +1,55 @@ +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AddonPathService_h +#define AddonPathService_h + +#include "amIAddonPathService.h" +#include "nsString.h" +#include "nsTArray.h" + +class nsIURI; +class JSAddonId; + +namespace mozilla { + +JSAddonId* +MapURIToAddonID(nsIURI* aURI); + +class AddonPathService final : public amIAddonPathService +{ +public: + AddonPathService(); + + static AddonPathService* GetInstance(); + + JSAddonId* Find(const nsAString& path); + static JSAddonId* FindAddonId(const nsAString& path); + + NS_DECL_ISUPPORTS + NS_DECL_AMIADDONPATHSERVICE + + struct PathEntry + { + nsString mPath; + JSAddonId* mAddonId; + + PathEntry(const nsAString& aPath, JSAddonId* aAddonId) + : mPath(aPath), mAddonId(aAddonId) + {} + }; + +private: + virtual ~AddonPathService(); + + // Paths are stored sorted in order of their mPath. + nsTArray mPaths; + + static AddonPathService* sInstance; +}; + +} // namespace mozilla + +#endif diff --git a/toolkit/mozapps/webextensions/ChromeManifestParser.jsm b/toolkit/mozapps/webextensions/ChromeManifestParser.jsm new file mode 100644 index 000000000..63f1db785 --- /dev/null +++ b/toolkit/mozapps/webextensions/ChromeManifestParser.jsm @@ -0,0 +1,157 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ChromeManifestParser"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +const MSG_JAR_FLUSH = "AddonJarFlush"; + + +/** + * Sends local and remote notifications to flush a JAR file cache entry + * + * @param aJarFile + * The ZIP/XPI/JAR file as a nsIFile + */ +function flushJarCache(aJarFile) { + Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null); + Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster) + .broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path); +} + + +/** + * Parses chrome manifest files. + */ +this.ChromeManifestParser = { + + /** + * Reads and parses a chrome manifest file located at a specified URI, and all + * secondary manifests it references. + * + * @param aURI + * A nsIURI pointing to a chrome manifest. + * Typically a file: or jar: URI. + * @return Array of objects describing each manifest instruction, in the form: + * { type: instruction-type, baseURI: string-uri, args: [arguments] } + **/ + parseSync: function(aURI) { + function parseLine(aLine) { + let line = aLine.trim(); + if (line.length == 0 || line.charAt(0) == '#') + return; + let tokens = line.split(/\s+/); + let type = tokens.shift(); + if (type == "manifest") { + let uri = NetUtil.newURI(tokens.shift(), null, aURI); + data = data.concat(this.parseSync(uri)); + } else { + data.push({type: type, baseURI: baseURI, args: tokens}); + } + } + + let contents = ""; + try { + if (aURI.scheme == "jar") + contents = this._readFromJar(aURI); + else + contents = this._readFromFile(aURI); + } catch (e) { + // Silently fail. + } + + if (!contents) + return []; + + let baseURI = NetUtil.newURI(".", null, aURI).spec; + + let data = []; + let lines = contents.split("\n"); + lines.forEach(parseLine.bind(this)); + return data; + }, + + _readFromJar: function(aURI) { + let data = ""; + let entries = []; + let readers = []; + + try { + // Deconstrict URI, which can be nested jar: URIs. + let uri = aURI.clone(); + while (uri instanceof Ci.nsIJARURI) { + entries.push(uri.JAREntry); + uri = uri.JARFile; + } + + // Open the base jar. + let reader = Cc["@mozilla.org/libjar/zip-reader;1"]. + createInstance(Ci.nsIZipReader); + reader.open(uri.QueryInterface(Ci.nsIFileURL).file); + readers.push(reader); + + // Open the nested jars. + for (let i = entries.length - 1; i > 0; i--) { + let innerReader = Cc["@mozilla.org/libjar/zip-reader;1"]. + createInstance(Ci.nsIZipReader); + innerReader.openInner(reader, entries[i]); + readers.push(innerReader); + reader = innerReader; + } + + // First entry is the actual file we want to read. + let zis = reader.getInputStream(entries[0]); + data = NetUtil.readInputStreamToString(zis, zis.available()); + } + finally { + // Close readers in reverse order. + for (let i = readers.length - 1; i >= 0; i--) { + readers[i].close(); + flushJarCache(readers[i].file); + } + } + + return data; + }, + + _readFromFile: function(aURI) { + let file = aURI.QueryInterface(Ci.nsIFileURL).file; + if (!file.exists() || !file.isFile()) + return ""; + + let data = ""; + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + try { + fis.init(file, -1, -1, false); + data = NetUtil.readInputStreamToString(fis, fis.available()); + } finally { + fis.close(); + } + return data; + }, + + /** + * Detects if there were any instructions of a specified type in a given + * chrome manifest. + * + * @param aManifest + * Manifest data, as returned by ChromeManifestParser.parseSync(). + * @param aType + * Instruction type to filter by. + * @return True if any matching instructions were found in the manifest. + */ + hasType: function(aManifest, aType) { + return aManifest.some(entry => entry.type == aType); + } +}; diff --git a/toolkit/mozapps/webextensions/DeferredSave.jsm b/toolkit/mozapps/webextensions/DeferredSave.jsm new file mode 100644 index 000000000..89f82b265 --- /dev/null +++ b/toolkit/mozapps/webextensions/DeferredSave.jsm @@ -0,0 +1,275 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/osfile.jsm"); +/* globals OS*/ +Cu.import("resource://gre/modules/Promise.jsm"); + +// Make it possible to mock out timers for testing +var MakeTimer = () => Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + +this.EXPORTED_SYMBOLS = ["DeferredSave"]; + +// If delay parameter is not provided, default is 50 milliseconds. +const DEFAULT_SAVE_DELAY_MS = 50; + +Cu.import("resource://gre/modules/Log.jsm"); +// Configure a logger at the parent 'DeferredSave' level to format +// messages for all the modules under DeferredSave.* +const DEFERREDSAVE_PARENT_LOGGER_ID = "DeferredSave"; +var parentLogger = Log.repository.getLogger(DEFERREDSAVE_PARENT_LOGGER_ID); +parentLogger.level = Log.Level.Warn; +var formatter = new Log.BasicFormatter(); +// Set parent logger (and its children) to append to +// the Javascript section of the Browser Console +parentLogger.addAppender(new Log.ConsoleAppender(formatter)); +// Set parent logger (and its children) to +// also append to standard out +parentLogger.addAppender(new Log.DumpAppender(formatter)); + +// Provide the ability to enable/disable logging +// messages at runtime. +// If the "extensions.logging.enabled" preference is +// missing or 'false', messages at the WARNING and higher +// severity should be logged to the JS console and standard error. +// If "extensions.logging.enabled" is set to 'true', messages +// at DEBUG and higher should go to JS console and standard error. +Cu.import("resource://gre/modules/Services.jsm"); + +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; + +/** +* Preference listener which listens for a change in the +* "extensions.logging.enabled" preference and changes the logging level of the +* parent 'addons' level logger accordingly. +*/ +var PrefObserver = { + init: function() { + Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); + Services.obs.addObserver(this, "xpcom-shutdown", false); + this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); + }, + + observe: function(aSubject, aTopic, aData) { + if (aTopic == "xpcom-shutdown") { + Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + } + else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { + let debugLogEnabled = false; + try { + debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); + } + catch (e) { + } + if (debugLogEnabled) { + parentLogger.level = Log.Level.Debug; + } + else { + parentLogger.level = Log.Level.Warn; + } + } + } +}; + +PrefObserver.init(); + +/** + * A module to manage deferred, asynchronous writing of data files + * to disk. Writing is deferred by waiting for a specified delay after + * a request to save the data, before beginning to write. If more than + * one save request is received during the delay, all requests are + * fulfilled by a single write. + * + * @constructor + * @param aPath + * String representing the full path of the file where the data + * is to be written. + * @param aDataProvider + * Callback function that takes no argument and returns the data to + * be written. If aDataProvider returns an ArrayBufferView, the + * bytes it contains are written to the file as is. + * If aDataProvider returns a String the data are UTF-8 encoded + * and then written to the file. + * @param [optional] aDelay + * The delay in milliseconds between the first saveChanges() call + * that marks the data as needing to be saved, and when the DeferredSave + * begins writing the data to disk. Default 50 milliseconds. + */ +this.DeferredSave = function(aPath, aDataProvider, aDelay) { + // Create a new logger (child of 'DeferredSave' logger) + // for use by this particular instance of DeferredSave object + let leafName = OS.Path.basename(aPath); + let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName; + this.logger = Log.repository.getLogger(logger_id); + + // @type {Deferred|null}, null when no data needs to be written + // @resolves with the result of OS.File.writeAtomic when all writes complete + // @rejects with the error from OS.File.writeAtomic if the write fails, + // or with the error from aDataProvider() if that throws. + this._pending = null; + + // @type {Promise}, completes when the in-progress write (if any) completes, + // kept as a resolved promise at other times to simplify logic. + // Because _deferredSave() always uses _writing.then() to execute + // its next action, we don't need a special case for whether a write + // is in progress - if the previous write is complete (and the _writing + // promise is already resolved/rejected), _writing.then() starts + // the next action immediately. + // + // @resolves with the result of OS.File.writeAtomic + // @rejects with the error from OS.File.writeAtomic + this._writing = Promise.resolve(0); + + // Are we currently waiting for a write to complete + this.writeInProgress = false; + + this._path = aPath; + this._dataProvider = aDataProvider; + + this._timer = null; + + // Some counters for telemetry + // The total number of times the file was written + this.totalSaves = 0; + + // The number of times the data became dirty while + // another save was in progress + this.overlappedSaves = 0; + + // Error returned by the most recent write (if any) + this._lastError = null; + + if (aDelay && (aDelay > 0)) + this._delay = aDelay; + else + this._delay = DEFAULT_SAVE_DELAY_MS; +} + +this.DeferredSave.prototype = { + get dirty() { + return this._pending || this.writeInProgress; + }, + + get lastError() { + return this._lastError; + }, + + // Start the pending timer if data is dirty + _startTimer: function() { + if (!this._pending) { + return; + } + + this.logger.debug("Starting timer"); + if (!this._timer) + this._timer = MakeTimer(); + this._timer.initWithCallback(() => this._deferredSave(), + this._delay, Ci.nsITimer.TYPE_ONE_SHOT); + }, + + /** + * Mark the current stored data dirty, and schedule a flush to disk + * @return A Promise that will be resolved after the data is written to disk; + * the promise is resolved with the number of bytes written. + */ + saveChanges: function() { + this.logger.debug("Save changes"); + if (!this._pending) { + if (this.writeInProgress) { + this.logger.debug("Data changed while write in progress"); + this.overlappedSaves++; + } + this._pending = Promise.defer(); + // Wait until the most recent write completes or fails (if it hasn't already) + // and then restart our timer + this._writing.then(count => this._startTimer(), error => this._startTimer()); + } + return this._pending.promise; + }, + + _deferredSave: function() { + let pending = this._pending; + this._pending = null; + let writing = this._writing; + this._writing = pending.promise; + + // In either the success or the exception handling case, we don't need to handle + // the error from _writing here; it's already being handled in another then() + let toSave = null; + try { + toSave = this._dataProvider(); + } + catch (e) { + this.logger.error("Deferred save dataProvider failed", e); + writing.then(null, error => {}) + .then(count => { + pending.reject(e); + }); + return; + } + + writing.then(null, error => { return 0; }) + .then(count => { + this.logger.debug("Starting write"); + this.totalSaves++; + this.writeInProgress = true; + + OS.File.writeAtomic(this._path, toSave, {tmpPath: this._path + ".tmp"}) + .then( + result => { + this._lastError = null; + this.writeInProgress = false; + this.logger.debug("Write succeeded"); + pending.resolve(result); + }, + error => { + this._lastError = error; + this.writeInProgress = false; + this.logger.warn("Write failed", error); + pending.reject(error); + }); + }); + }, + + /** + * Immediately save the dirty data to disk, skipping + * the delay of normal operation. Note that the write + * still happens asynchronously in the worker + * thread from OS.File. + * + * There are four possible situations: + * 1) Nothing to flush + * 2) Data is not currently being written, in-memory copy is dirty + * 3) Data is currently being written, in-memory copy is clean + * 4) Data is being written and in-memory copy is dirty + * + * @return Promise that will resolve when all in-memory data + * has finished being flushed, returning the number of bytes + * written. If all in-memory data is clean, completes with the + * result of the most recent write. + */ + flush: function() { + // If we have pending changes, cancel our timer and set up the write + // immediately (_deferredSave queues the write for after the most + // recent write completes, if it hasn't already) + if (this._pending) { + this.logger.debug("Flush called while data is dirty"); + if (this._timer) { + this._timer.cancel(); + this._timer = null; + } + this._deferredSave(); + } + + return this._writing; + } +}; diff --git a/toolkit/mozapps/webextensions/LightweightThemeManager.jsm b/toolkit/mozapps/webextensions/LightweightThemeManager.jsm new file mode 100644 index 000000000..5dd41831d --- /dev/null +++ b/toolkit/mozapps/webextensions/LightweightThemeManager.jsm @@ -0,0 +1,909 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["LightweightThemeManager"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/AddonManager.jsm"); +/* globals AddonManagerPrivate*/ +Components.utils.import("resource://gre/modules/Services.jsm"); + +const ID_SUFFIX = "@personas.mozilla.org"; +const PREF_LWTHEME_TO_SELECT = "extensions.lwThemeToSelect"; +const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin"; +const PREF_EM_DSS_ENABLED = "extensions.dss.enabled"; +const ADDON_TYPE = "theme"; + +const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; + +const STRING_TYPE_NAME = "type.%ID%.name"; + +const DEFAULT_MAX_USED_THEMES_COUNT = 30; + +const MAX_PREVIEW_SECONDS = 30; + +const MANDATORY = ["id", "name", "headerURL"]; +const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL", + "previewURL", "author", "description", "homepageURL", + "updateURL", "version"]; + +const PERSIST_ENABLED = true; +const PERSIST_BYPASS_CACHE = false; +const PERSIST_FILES = { + headerURL: "lightweighttheme-header", + footerURL: "lightweighttheme-footer" +}; + +XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", + "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest", + "resource://gre/modules/ServiceRequest.jsm"); + + +XPCOMUtils.defineLazyGetter(this, "_prefs", () => { + return Services.prefs.getBranch("lightweightThemes."); +}); + +Object.defineProperty(this, "_maxUsedThemes", { + get: function() { + delete this._maxUsedThemes; + try { + this._maxUsedThemes = _prefs.getIntPref("maxUsedThemes"); + } + catch (e) { + this._maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; + } + return this._maxUsedThemes; + }, + + set: function(val) { + delete this._maxUsedThemes; + return this._maxUsedThemes = val; + }, + configurable: true, +}); + +// Holds the ID of the theme being enabled or disabled while sending out the +// events so cached AddonWrapper instances can return correct values for +// permissions and pendingOperations +var _themeIDBeingEnabled = null; +var _themeIDBeingDisabled = null; + +// Convert from the old storage format (in which the order of usedThemes +// was combined with isThemeSelected to determine which theme was selected) +// to the new one (where a selectedThemeID determines which theme is selected). +(function() { + let wasThemeSelected = false; + try { + wasThemeSelected = _prefs.getBoolPref("isThemeSelected"); + } catch (e) { } + + if (wasThemeSelected) { + _prefs.clearUserPref("isThemeSelected"); + let themes = []; + try { + themes = JSON.parse(_prefs.getComplexValue("usedThemes", + Ci.nsISupportsString).data); + } catch (e) { } + + if (Array.isArray(themes) && themes[0]) { + _prefs.setCharPref("selectedThemeID", themes[0].id); + } + } +})(); + +this.LightweightThemeManager = { + get name() { + return "LightweightThemeManager"; + }, + + // Themes that can be added for an application. They can't be removed, and + // will always show up at the top of the list. + _builtInThemes: new Map(), + + get usedThemes () { + let themes = []; + try { + themes = JSON.parse(_prefs.getComplexValue("usedThemes", + Ci.nsISupportsString).data); + } catch (e) { } + + themes.push(...this._builtInThemes.values()); + return themes; + }, + + get currentTheme () { + let selectedThemeID = null; + try { + selectedThemeID = _prefs.getCharPref("selectedThemeID"); + } catch (e) {} + + let data = null; + if (selectedThemeID) { + data = this.getUsedTheme(selectedThemeID); + } + return data; + }, + + get currentThemeForDisplay () { + var data = this.currentTheme; + + if (data && PERSIST_ENABLED) { + for (let key in PERSIST_FILES) { + try { + if (data[key] && _prefs.getBoolPref("persisted." + key)) + data[key] = _getLocalImageURI(PERSIST_FILES[key]).spec + + "?" + data.id + ";" + _version(data); + } catch (e) {} + } + } + + return data; + }, + + set currentTheme (aData) { + return _setCurrentTheme(aData, false); + }, + + setLocalTheme: function(aData) { + _setCurrentTheme(aData, true); + }, + + getUsedTheme: function(aId) { + var usedThemes = this.usedThemes; + for (let usedTheme of usedThemes) { + if (usedTheme.id == aId) + return usedTheme; + } + return null; + }, + + forgetUsedTheme: function(aId) { + let theme = this.getUsedTheme(aId); + if (!theme || LightweightThemeManager._builtInThemes.has(theme.id)) + return; + + let wrapper = new AddonWrapper(theme); + AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); + + var currentTheme = this.currentTheme; + if (currentTheme && currentTheme.id == aId) { + this.themeChanged(null); + AddonManagerPrivate.notifyAddonChanged(null, ADDON_TYPE, false); + } + + _updateUsedThemes(_usedThemesExceptId(aId)); + AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); + }, + + addBuiltInTheme: function(theme) { + if (!theme || !theme.id || this.usedThemes.some(t => t.id == theme.id)) { + throw new Error("Trying to add invalid builtIn theme"); + } + + this._builtInThemes.set(theme.id, theme); + + if (_prefs.getCharPref("selectedThemeID") == theme.id) { + this.currentTheme = theme; + } + }, + + forgetBuiltInTheme: function(id) { + if (!this._builtInThemes.has(id)) { + let currentTheme = this.currentTheme; + if (currentTheme && currentTheme.id == id) { + this.currentTheme = null; + } + } + return this._builtInThemes.delete(id); + }, + + clearBuiltInThemes: function() { + for (let id of this._builtInThemes.keys()) { + this.forgetBuiltInTheme(id); + } + }, + + previewTheme: function(aData) { + let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + cancel.data = false; + Services.obs.notifyObservers(cancel, "lightweight-theme-preview-requested", + JSON.stringify(aData)); + if (cancel.data) + return; + + if (_previewTimer) + _previewTimer.cancel(); + else + _previewTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + _previewTimer.initWithCallback(_previewTimerCallback, + MAX_PREVIEW_SECONDS * 1000, + _previewTimer.TYPE_ONE_SHOT); + + _notifyWindows(aData); + }, + + resetPreview: function() { + if (_previewTimer) { + _previewTimer.cancel(); + _previewTimer = null; + _notifyWindows(this.currentThemeForDisplay); + } + }, + + parseTheme: function(aString, aBaseURI) { + try { + return _sanitizeTheme(JSON.parse(aString), aBaseURI, false); + } catch (e) { + return null; + } + }, + + updateCurrentTheme: function() { + try { + if (!_prefs.getBoolPref("update.enabled")) + return; + } catch (e) { + return; + } + + var theme = this.currentTheme; + if (!theme || !theme.updateURL) + return; + + var req = new ServiceRequest(); + + req.mozBackgroundRequest = true; + req.overrideMimeType("text/plain"); + req.open("GET", theme.updateURL, true); + // Prevent the request from reading from the cache. + req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; + // Prevent the request from writing to the cache. + req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; + + req.addEventListener("load", () => { + if (req.status != 200) + return; + + let newData = this.parseTheme(req.responseText, theme.updateURL); + if (!newData || + newData.id != theme.id || + _version(newData) == _version(theme)) + return; + + var currentTheme = this.currentTheme; + if (currentTheme && currentTheme.id == theme.id) + this.currentTheme = newData; + }, false); + + req.send(null); + }, + + /** + * Switches to a new lightweight theme. + * + * @param aData + * The lightweight theme to switch to + */ + themeChanged: function(aData) { + if (_previewTimer) { + _previewTimer.cancel(); + _previewTimer = null; + } + + if (aData) { + let usedThemes = _usedThemesExceptId(aData.id); + usedThemes.unshift(aData); + _updateUsedThemes(usedThemes); + if (PERSIST_ENABLED) { + LightweightThemeImageOptimizer.purge(); + _persistImages(aData, function() { + _notifyWindows(this.currentThemeForDisplay); + }.bind(this)); + } + } + + if (aData) + _prefs.setCharPref("selectedThemeID", aData.id); + else + _prefs.setCharPref("selectedThemeID", ""); + + _notifyWindows(aData); + Services.obs.notifyObservers(null, "lightweight-theme-changed", null); + }, + + /** + * Starts the Addons provider and enables the new lightweight theme if + * necessary. + */ + startup: function() { + if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) { + let id = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + if (id) + this.themeChanged(this.getUsedTheme(id)); + else + this.themeChanged(null); + Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); + } + + _prefs.addObserver("", _prefObserver, false); + }, + + /** + * Shuts down the provider. + */ + shutdown: function() { + _prefs.removeObserver("", _prefObserver); + }, + + /** + * Called when a new add-on has been enabled when only one add-on of that type + * can be enabled. + * + * @param aId + * The ID of the newly enabled add-on + * @param aType + * The type of the newly enabled add-on + * @param aPendingRestart + * true if the newly enabled add-on will only become enabled after a + * restart + */ + addonChanged: function(aId, aType, aPendingRestart) { + if (aType != ADDON_TYPE) + return; + + let id = _getInternalID(aId); + let current = this.currentTheme; + + try { + let next = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + if (id == next && aPendingRestart) + return; + + Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); + if (next) { + AddonManagerPrivate.callAddonListeners("onOperationCancelled", + new AddonWrapper(this.getUsedTheme(next))); + } + else if (id == current.id) { + AddonManagerPrivate.callAddonListeners("onOperationCancelled", + new AddonWrapper(current)); + return; + } + } + catch (e) { + } + + if (current) { + if (current.id == id) + return; + _themeIDBeingDisabled = current.id; + let wrapper = new AddonWrapper(current); + if (aPendingRestart) { + Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, ""); + AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, true); + } + else { + AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false); + this.themeChanged(null); + AddonManagerPrivate.callAddonListeners("onDisabled", wrapper); + } + _themeIDBeingDisabled = null; + } + + if (id) { + let theme = this.getUsedTheme(id); + _themeIDBeingEnabled = id; + let wrapper = new AddonWrapper(theme); + if (aPendingRestart) { + AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, true); + Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, id); + + // Flush the preferences to disk so they survive any crash + Services.prefs.savePrefFile(null); + } + else { + AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false); + this.themeChanged(theme); + AddonManagerPrivate.callAddonListeners("onEnabled", wrapper); + } + _themeIDBeingEnabled = null; + } + }, + + /** + * Called to get an Addon with a particular ID. + * + * @param aId + * The ID of the add-on to retrieve + * @param aCallback + * A callback to pass the Addon to + */ + getAddonByID: function(aId, aCallback) { + let id = _getInternalID(aId); + if (!id) { + aCallback(null); + return; + } + + let theme = this.getUsedTheme(id); + if (!theme) { + aCallback(null); + return; + } + + aCallback(new AddonWrapper(theme)); + }, + + /** + * Called to get Addons of a particular type. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types. + * @param aCallback + * A callback to pass an array of Addons to + */ + getAddonsByTypes: function(aTypes, aCallback) { + if (aTypes && aTypes.indexOf(ADDON_TYPE) == -1) { + aCallback([]); + return; + } + + aCallback(this.usedThemes.map(a => new AddonWrapper(a))); + }, +}; + +const wrapperMap = new WeakMap(); +let themeFor = wrapper => wrapperMap.get(wrapper); + +/** + * The AddonWrapper wraps lightweight theme to provide the data visible to + * consumers of the AddonManager API. + */ +function AddonWrapper(aTheme) { + wrapperMap.set(this, aTheme); +} + +AddonWrapper.prototype = { + get id() { + return themeFor(this).id + ID_SUFFIX; + }, + + get type() { + return ADDON_TYPE; + }, + + get isActive() { + let current = LightweightThemeManager.currentTheme; + if (current) + return themeFor(this).id == current.id; + return false; + }, + + get name() { + return themeFor(this).name; + }, + + get version() { + let theme = themeFor(this); + return "version" in theme ? theme.version : ""; + }, + + get creator() { + let theme = themeFor(this); + return "author" in theme ? new AddonManagerPrivate.AddonAuthor(theme.author) : null; + }, + + get screenshots() { + let url = themeFor(this).previewURL; + return [new AddonManagerPrivate.AddonScreenshot(url)]; + }, + + get pendingOperations() { + let pending = AddonManager.PENDING_NONE; + if (this.isActive == this.userDisabled) + pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE; + return pending; + }, + + get operationsRequiringRestart() { + // If a non-default theme is in use then a restart will be required to + // enable lightweight themes unless dynamic theme switching is enabled + if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN)) { + try { + if (Services.prefs.getBoolPref(PREF_EM_DSS_ENABLED)) + return AddonManager.OP_NEEDS_RESTART_NONE; + } + catch (e) { + } + return AddonManager.OP_NEEDS_RESTART_ENABLE; + } + + return AddonManager.OP_NEEDS_RESTART_NONE; + }, + + get size() { + // The size changes depending on whether the theme is in use or not, this is + // probably not worth exposing. + return null; + }, + + get permissions() { + let permissions = 0; + + // Do not allow uninstall of builtIn themes. + if (!LightweightThemeManager._builtInThemes.has(themeFor(this).id)) + permissions = AddonManager.PERM_CAN_UNINSTALL; + if (this.userDisabled) + permissions |= AddonManager.PERM_CAN_ENABLE; + else + permissions |= AddonManager.PERM_CAN_DISABLE; + return permissions; + }, + + get userDisabled() { + let id = themeFor(this).id; + if (_themeIDBeingEnabled == id) + return false; + if (_themeIDBeingDisabled == id) + return true; + + try { + let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + return id != toSelect; + } + catch (e) { + let current = LightweightThemeManager.currentTheme; + return !current || current.id != id; + } + }, + + set userDisabled(val) { + if (val == this.userDisabled) + return val; + + if (val) + LightweightThemeManager.currentTheme = null; + else + LightweightThemeManager.currentTheme = themeFor(this); + + return val; + }, + + // Lightweight themes are never disabled by the application + get appDisabled() { + return false; + }, + + // Lightweight themes are always compatible + get isCompatible() { + return true; + }, + + get isPlatformCompatible() { + return true; + }, + + get scope() { + return AddonManager.SCOPE_PROFILE; + }, + + get foreignInstall() { + return false; + }, + + uninstall: function() { + LightweightThemeManager.forgetUsedTheme(themeFor(this).id); + }, + + cancelUninstall: function() { + throw new Error("Theme is not marked to be uninstalled"); + }, + + findUpdates: function(listener, reason, appVersion, platformVersion) { + AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion); + }, + + // Lightweight themes are always compatible + isCompatibleWith: function(appVersion, platformVersion) { + return true; + }, + + // Lightweight themes are always securely updated + get providesUpdatesSecurely() { + return true; + }, + + // Lightweight themes are never blocklisted + get blocklistState() { + return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + } +}; + +["description", "homepageURL", "iconURL"].forEach(function(prop) { + Object.defineProperty(AddonWrapper.prototype, prop, { + get: function() { + let theme = themeFor(this); + return prop in theme ? theme[prop] : null; + }, + enumarable: true, + }); +}); + +["installDate", "updateDate"].forEach(function(prop) { + Object.defineProperty(AddonWrapper.prototype, prop, { + get: function() { + let theme = themeFor(this); + return prop in theme ? new Date(theme[prop]) : null; + }, + enumarable: true, + }); +}); + +/** + * Converts the ID used by the public AddonManager API to an lightweight theme + * ID. + * + * @param id + * The ID to be converted + * + * @return the lightweight theme ID or null if the ID was not for a lightweight + * theme. + */ +function _getInternalID(id) { + if (!id) + return null; + let len = id.length - ID_SUFFIX.length; + if (len > 0 && id.substring(len) == ID_SUFFIX) + return id.substring(0, len); + return null; +} + +function _setCurrentTheme(aData, aLocal) { + aData = _sanitizeTheme(aData, null, aLocal); + + let needsRestart = (ADDON_TYPE == "theme") && + Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN); + + let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + cancel.data = false; + Services.obs.notifyObservers(cancel, "lightweight-theme-change-requested", + JSON.stringify(aData)); + + if (aData) { + let theme = LightweightThemeManager.getUsedTheme(aData.id); + let isInstall = !theme || theme.version != aData.version; + if (isInstall) { + aData.updateDate = Date.now(); + if (theme && "installDate" in theme) + aData.installDate = theme.installDate; + else + aData.installDate = aData.updateDate; + + var oldWrapper = theme ? new AddonWrapper(theme) : null; + var wrapper = new AddonWrapper(aData); + AddonManagerPrivate.callInstallListeners("onExternalInstall", null, + wrapper, oldWrapper, false); + AddonManagerPrivate.callAddonListeners("onInstalling", wrapper, false); + } + + let current = LightweightThemeManager.currentTheme; + let usedThemes = _usedThemesExceptId(aData.id); + if (current && current.id != aData.id) + usedThemes.splice(1, 0, aData); + else + usedThemes.unshift(aData); + _updateUsedThemes(usedThemes); + + if (isInstall) + AddonManagerPrivate.callAddonListeners("onInstalled", wrapper); + } + + if (cancel.data) + return null; + + AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null, + ADDON_TYPE, needsRestart); + + return LightweightThemeManager.currentTheme; +} + +function _sanitizeTheme(aData, aBaseURI, aLocal) { + if (!aData || typeof aData != "object") + return null; + + var resourceProtocols = ["http", "https", "resource"]; + if (aLocal) + resourceProtocols.push("file"); + var resourceProtocolExp = new RegExp("^(" + resourceProtocols.join("|") + "):"); + + function sanitizeProperty(prop) { + if (!(prop in aData)) + return null; + if (typeof aData[prop] != "string") + return null; + let val = aData[prop].trim(); + if (!val) + return null; + + if (!/URL$/.test(prop)) + return val; + + try { + val = _makeURI(val, aBaseURI ? _makeURI(aBaseURI) : null).spec; + if ((prop == "updateURL" ? /^https:/ : resourceProtocolExp).test(val)) + return val; + return null; + } + catch (e) { + return null; + } + } + + let result = {}; + for (let mandatoryProperty of MANDATORY) { + let val = sanitizeProperty(mandatoryProperty); + if (!val) + throw Components.results.NS_ERROR_INVALID_ARG; + result[mandatoryProperty] = val; + } + + for (let optionalProperty of OPTIONAL) { + let val = sanitizeProperty(optionalProperty); + if (!val) + continue; + result[optionalProperty] = val; + } + + return result; +} + +function _usedThemesExceptId(aId) { + return LightweightThemeManager.usedThemes.filter(function(t) { + return "id" in t && t.id != aId; + }); +} + +function _version(aThemeData) { + return aThemeData.version || ""; +} + +function _makeURI(aURL, aBaseURI) { + return Services.io.newURI(aURL, null, aBaseURI); +} + +function _updateUsedThemes(aList) { + // Remove app-specific themes before saving them to the usedThemes pref. + aList = aList.filter(theme => !LightweightThemeManager._builtInThemes.has(theme.id)); + + // Send uninstall events for all themes that need to be removed. + while (aList.length > _maxUsedThemes) { + let wrapper = new AddonWrapper(aList[aList.length - 1]); + AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); + aList.pop(); + AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); + } + + var str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = JSON.stringify(aList); + _prefs.setComplexValue("usedThemes", Ci.nsISupportsString, str); + + Services.obs.notifyObservers(null, "lightweight-theme-list-changed", null); +} + +function _notifyWindows(aThemeData) { + Services.obs.notifyObservers(null, "lightweight-theme-styling-update", + JSON.stringify(aThemeData)); +} + +var _previewTimer; +var _previewTimerCallback = { + notify: function() { + LightweightThemeManager.resetPreview(); + } +}; + +/** + * Called when any of the lightweightThemes preferences are changed. + */ +function _prefObserver(aSubject, aTopic, aData) { + switch (aData) { + case "maxUsedThemes": + try { + _maxUsedThemes = _prefs.getIntPref(aData); + } + catch (e) { + _maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; + } + // Update the theme list to remove any themes over the number we keep + _updateUsedThemes(LightweightThemeManager.usedThemes); + break; + } +} + +function _persistImages(aData, aCallback) { + function onSuccess(key) { + return function () { + let current = LightweightThemeManager.currentTheme; + if (current && current.id == aData.id) { + _prefs.setBoolPref("persisted." + key, true); + } + if (--numFilesToPersist == 0 && aCallback) { + aCallback(); + } + }; + } + + let numFilesToPersist = 0; + for (let key in PERSIST_FILES) { + _prefs.setBoolPref("persisted." + key, false); + if (aData[key]) { + numFilesToPersist++; + _persistImage(aData[key], PERSIST_FILES[key], onSuccess(key)); + } + } +} + +function _getLocalImageURI(localFileName) { + var localFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + localFile.append(localFileName); + return Services.io.newFileURI(localFile); +} + +function _persistImage(sourceURL, localFileName, successCallback) { + if (/^(file|resource):/.test(sourceURL)) + return; + + var targetURI = _getLocalImageURI(localFileName); + var sourceURI = _makeURI(sourceURL); + + var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + + persist.persistFlags = + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION | + (PERSIST_BYPASS_CACHE ? + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE : + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE); + + persist.progressListener = new _persistProgressListener(successCallback); + + persist.saveURI(sourceURI, null, + null, Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, + null, null, targetURI, null); +} + +function _persistProgressListener(successCallback) { + this.onLocationChange = function() {}; + this.onProgressChange = function() {}; + this.onStatusChange = function() {}; + this.onSecurityChange = function() {}; + this.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus) { + if (aRequest && + aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK && + aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) { + try { + if (aRequest.QueryInterface(Ci.nsIHttpChannel).requestSucceeded) { + // success + successCallback(); + return; + } + } catch (e) { } + // failure + } + }; +} + +AddonManagerPrivate.registerProvider(LightweightThemeManager, [ + new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS, + STRING_TYPE_NAME, + AddonManager.VIEW_TYPE_LIST, 5000) +]); diff --git a/toolkit/mozapps/webextensions/addonManager.js b/toolkit/mozapps/webextensions/addonManager.js new file mode 100644 index 000000000..d34cbaf62 --- /dev/null +++ b/toolkit/mozapps/webextensions/addonManager.js @@ -0,0 +1,296 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This component serves as integration between the platform and AddonManager. + * It is responsible for initializing and shutting down the AddonManager as well + * as passing new installs from webpages to the AddonManager. + */ + +"use strict"; + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +// The old XPInstall error codes +const EXECUTION_ERROR = -203; +const CANT_READ_ARCHIVE = -207; +const USER_CANCELLED = -210; +const DOWNLOAD_ERROR = -228; +const UNSUPPORTED_TYPE = -244; +const SUCCESS = 0; + +const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; + +const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest"; +const MSG_PROMISE_RESULT = "WebAPIPromiseResult"; +const MSG_INSTALL_EVENT = "WebAPIInstallEvent"; +const MSG_INSTALL_CLEANUP = "WebAPICleanup"; +const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest"; +const MSG_ADDON_EVENT = "WebAPIAddonEvent"; + +const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js"; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +var gSingleton = null; + +function amManager() { + Cu.import("resource://gre/modules/AddonManager.jsm"); + /* globals AddonManagerPrivate*/ + + Services.mm.loadFrameScript(CHILD_SCRIPT, true); + Services.mm.addMessageListener(MSG_INSTALL_ENABLED, this); + Services.mm.addMessageListener(MSG_INSTALL_ADDONS, this); + Services.mm.addMessageListener(MSG_PROMISE_REQUEST, this); + Services.mm.addMessageListener(MSG_INSTALL_CLEANUP, this); + Services.mm.addMessageListener(MSG_ADDON_EVENT_REQ, this); + + Services.obs.addObserver(this, "message-manager-close", false); + Services.obs.addObserver(this, "message-manager-disconnect", false); + + AddonManager.webAPI.setEventHandler(this.sendEvent); + + // Needed so receiveMessage can be called directly by JS callers + this.wrappedJSObject = this; +} + +amManager.prototype = { + observe: function(aSubject, aTopic, aData) { + switch (aTopic) { + case "addons-startup": + AddonManagerPrivate.startup(); + break; + + case "message-manager-close": + case "message-manager-disconnect": + this.childClosed(aSubject); + break; + } + }, + + /** + * @see amIAddonManager.idl + */ + mapURIToAddonID: function(uri, id) { + id.value = AddonManager.mapURIToAddonID(uri); + return !!id.value; + }, + + /** + * @see amIWebInstaller.idl + */ + isInstallEnabled: function(aMimetype, aReferer) { + return AddonManager.isInstallEnabled(aMimetype); + }, + + /** + * @see amIWebInstaller.idl + */ + installAddonsFromWebpage: function(aMimetype, aBrowser, aInstallingPrincipal, + aUris, aHashes, aNames, aIcons, aCallback) { + if (aUris.length == 0) + return false; + + let retval = true; + if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) { + aCallback = null; + retval = false; + } + + let installs = []; + function buildNextInstall() { + if (aUris.length == 0) { + AddonManager.installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, installs); + return; + } + let uri = aUris.shift(); + AddonManager.getInstallForURL(uri, function(aInstall) { + function callCallback(aUri, aStatus) { + try { + aCallback.onInstallEnded(aUri, aStatus); + } + catch (e) { + Components.utils.reportError(e); + } + } + + if (aInstall) { + installs.push(aInstall); + if (aCallback) { + aInstall.addListener({ + onDownloadCancelled: function(aInstall) { + callCallback(uri, USER_CANCELLED); + }, + + onDownloadFailed: function(aInstall) { + if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) + callCallback(uri, CANT_READ_ARCHIVE); + else + callCallback(uri, DOWNLOAD_ERROR); + }, + + onInstallFailed: function(aInstall) { + callCallback(uri, EXECUTION_ERROR); + }, + + onInstallEnded: function(aInstall, aStatus) { + callCallback(uri, SUCCESS); + } + }); + } + } + else if (aCallback) { + aCallback.onInstallEnded(uri, UNSUPPORTED_TYPE); + } + buildNextInstall(); + }, aMimetype, aHashes.shift(), aNames.shift(), aIcons.shift(), null, aBrowser); + } + buildNextInstall(); + + return retval; + }, + + notify: function(aTimer) { + AddonManagerPrivate.backgroundUpdateTimerHandler(); + }, + + // Maps message manager instances for content processes to the associated + // AddonListener instances. + addonListeners: new Map(), + + _addAddonListener(target) { + if (!this.addonListeners.has(target)) { + let handler = (event, id, needsRestart) => { + target.sendAsyncMessage(MSG_ADDON_EVENT, {event, id, needsRestart}); + }; + let listener = { + onEnabling: (addon, needsRestart) => handler("onEnabling", addon.id, needsRestart), + onEnabled: (addon) => handler("onEnabled", addon.id, false), + onDisabling: (addon, needsRestart) => handler("onDisabling", addon.id, needsRestart), + onDisabled: (addon) => handler("onDisabled", addon.id, false), + onInstalling: (addon, needsRestart) => handler("onInstalling", addon.id, needsRestart), + onInstalled: (addon) => handler("onInstalled", addon.id, false), + onUninstalling: (addon, needsRestart) => handler("onUninstalling", addon.id, needsRestart), + onUninstalled: (addon) => handler("onUninstalled", addon.id, false), + onOperationCancelled: (addon) => handler("onOperationCancelled", addon.id, false), + }; + this.addonListeners.set(target, listener); + AddonManager.addAddonListener(listener); + } + }, + + _removeAddonListener(target) { + if (this.addonListeners.has(target)) { + AddonManager.removeAddonListener(this.addonListeners.get(target)); + this.addonListeners.delete(target); + } + }, + + /** + * messageManager callback function. + * + * Listens to requests from child processes for InstallTrigger + * activity, and sends back callbacks. + */ + receiveMessage: function(aMessage) { + let payload = aMessage.data; + + switch (aMessage.name) { + case MSG_INSTALL_ENABLED: + return AddonManager.isInstallEnabled(payload.mimetype); + + case MSG_INSTALL_ADDONS: { + let callback = null; + if (payload.callbackID != -1) { + let mm = aMessage.target.messageManager; + callback = { + onInstallEnded: function(url, status) { + mm.sendAsyncMessage(MSG_INSTALL_CALLBACK, { + callbackID: payload.callbackID, + url: url, + status: status + }); + }, + }; + } + + return this.installAddonsFromWebpage(payload.mimetype, + aMessage.target, payload.triggeringPrincipal, payload.uris, + payload.hashes, payload.names, payload.icons, callback); + } + + case MSG_PROMISE_REQUEST: { + let mm = aMessage.target.messageManager; + let resolve = (value) => { + mm.sendAsyncMessage(MSG_PROMISE_RESULT, { + callbackID: payload.callbackID, + resolve: value + }); + } + let reject = (value) => { + mm.sendAsyncMessage(MSG_PROMISE_RESULT, { + callbackID: payload.callbackID, + reject: value + }); + } + + let API = AddonManager.webAPI; + if (payload.type in API) { + API[payload.type](aMessage.target, ...payload.args).then(resolve, reject); + } + else { + reject("Unknown Add-on API request."); + } + break; + } + + case MSG_INSTALL_CLEANUP: { + AddonManager.webAPI.clearInstalls(payload.ids); + break; + } + + case MSG_ADDON_EVENT_REQ: { + let target = aMessage.target.messageManager; + if (payload.enabled) { + this._addAddonListener(target); + } else { + this._removeAddonListener(target); + } + } + } + return undefined; + }, + + childClosed(target) { + AddonManager.webAPI.clearInstallsFrom(target); + this._removeAddonListener(target); + }, + + sendEvent(mm, data) { + mm.sendAsyncMessage(MSG_INSTALL_EVENT, data); + }, + + classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"), + _xpcom_factory: { + createInstance: function(aOuter, aIid) { + if (aOuter != null) + throw Components.Exception("Component does not support aggregation", + Cr.NS_ERROR_NO_AGGREGATION); + + if (!gSingleton) + gSingleton = new amManager(); + return gSingleton.QueryInterface(aIid); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.amIAddonManager, + Ci.amIWebInstaller, + Ci.nsITimerCallback, + Ci.nsIObserver, + Ci.nsIMessageListener]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amManager]); diff --git a/toolkit/mozapps/webextensions/amContentHandler.js b/toolkit/mozapps/webextensions/amContentHandler.js new file mode 100644 index 000000000..8dc4dfecd --- /dev/null +++ b/toolkit/mozapps/webextensions/amContentHandler.js @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +const XPI_CONTENT_TYPE = "application/x-xpinstall"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +function amContentHandler() { +} + +amContentHandler.prototype = { + /** + * Handles a new request for an application/x-xpinstall file. + * + * @param aMimetype + * The mimetype of the file + * @param aContext + * The context passed to nsIChannel.asyncOpen + * @param aRequest + * The nsIRequest dealing with the content + */ + handleContent: function(aMimetype, aContext, aRequest) { + if (aMimetype != XPI_CONTENT_TYPE) + throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; + + if (!(aRequest instanceof Ci.nsIChannel)) + throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; + + let uri = aRequest.URI; + + let window = null; + let callbacks = aRequest.notificationCallbacks ? + aRequest.notificationCallbacks : + aRequest.loadGroup.notificationCallbacks; + if (callbacks) + window = callbacks.getInterface(Ci.nsIDOMWindow); + + aRequest.cancel(Cr.NS_BINDING_ABORTED); + + let installs = { + uris: [uri.spec], + hashes: [null], + names: [null], + icons: [null], + mimetype: XPI_CONTENT_TYPE, + triggeringPrincipal: aRequest.loadInfo.triggeringPrincipal, + callbackID: -1 + }; + + if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // When running in the main process this might be a frame inside an + // in-content UI page, walk up to find the first frame element in a chrome + // privileged document + let element = window.frameElement; + let ssm = Services.scriptSecurityManager; + while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) + element = element.ownerDocument.defaultView.frameElement; + + if (element) { + let listener = Cc["@mozilla.org/addons/integration;1"]. + getService(Ci.nsIMessageListener); + listener.wrappedJSObject.receiveMessage({ + name: MSG_INSTALL_ADDONS, + target: element, + data: installs, + }); + return; + } + } + + // Fall back to sending through the message manager + let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + + messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs); + }, + + classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]), + + log : function(aMsg) { + let msg = "amContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg); + Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService). + logStringMessage(msg); + dump(msg + "\n"); + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amContentHandler]); diff --git a/toolkit/mozapps/webextensions/amIAddonManager.idl b/toolkit/mozapps/webextensions/amIAddonManager.idl new file mode 100644 index 000000000..58a58b62d --- /dev/null +++ b/toolkit/mozapps/webextensions/amIAddonManager.idl @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIURI; + +/** + * A service to make some AddonManager functionality available to C++ callers. + * Javascript callers should still use AddonManager.jsm directly. + */ +[scriptable, function, uuid(7b45d82d-7ad5-48d7-9b05-f32eb9818cd4)] +interface amIAddonManager : nsISupports +{ + /** + * Synchronously map a URI to the corresponding Addon ID. + * + * Mappable URIs are limited to in-application resources belonging to the + * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. + * but do not include URIs from meta data, such as the add-on homepage. + * + * @param aURI + * The nsIURI to map + * @return + * true if the URI has been mapped successfully to an Addon ID + */ + boolean mapURIToAddonID(in nsIURI aURI, out AUTF8String aID); +}; diff --git a/toolkit/mozapps/webextensions/amIAddonPathService.idl b/toolkit/mozapps/webextensions/amIAddonPathService.idl new file mode 100644 index 000000000..9c9197a61 --- /dev/null +++ b/toolkit/mozapps/webextensions/amIAddonPathService.idl @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIURI; + +/** + * This service maps file system paths where add-ons reside to the ID + * of the add-on. Paths are added by the add-on manager. They can + * looked up by anyone. + */ +[scriptable, uuid(fcd9e270-dfb1-11e3-8b68-0800200c9a66)] +interface amIAddonPathService : nsISupports +{ + /** + * Given a path to a file, return the ID of the add-on that the file belongs + * to. Returns an empty string if there is no add-on there. Note that if an + * add-on is located at /a/b/c, then looking up the path /a/b/c/d will return + * that add-on. + */ + AString findAddonId(in AString path); + + /** + * Call this function to inform the service that the given file system path is + * associated with the given add-on ID. + */ + void insertPath(in AString path, in AString addonId); + + /** + * Given a URI to a file, return the ID of the add-on that the file belongs + * to. Returns an empty string if there is no add-on there. + */ + AString mapURIToAddonId(in nsIURI aURI); +}; diff --git a/toolkit/mozapps/webextensions/amIWebInstallListener.idl b/toolkit/mozapps/webextensions/amIWebInstallListener.idl new file mode 100644 index 000000000..eed108097 --- /dev/null +++ b/toolkit/mozapps/webextensions/amIWebInstallListener.idl @@ -0,0 +1,134 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMElement; +interface nsIURI; +interface nsIVariant; + +/** + * amIWebInstallInfo is used by the default implementation of + * amIWebInstallListener to communicate with the running application and allow + * it to warn the user about blocked installs and start the installs running. + */ +[scriptable, uuid(fa0b47a3-f819-47ac-bc66-4bd1d7f67b1d)] +interface amIWebInstallInfo : nsISupports +{ + readonly attribute nsIDOMElement browser; + readonly attribute nsIURI originatingURI; + readonly attribute nsIVariant installs; + + /** + * Starts all installs. + */ + void install(); +}; + +/** + * The registered amIWebInstallListener is used to notify about new installs + * triggered by websites. The default implementation displays a confirmation + * dialog when add-ons are ready to install and uses the observer service to + * notify when installations are blocked. + */ +[scriptable, uuid(d9240d4b-6b3a-4cad-b402-de6c93337e0c)] +interface amIWebInstallListener : nsISupports +{ + /** + * Called when installation by websites is currently disabled. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + */ + void onWebInstallDisabled(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); + + /** + * Called when the website is not allowed to directly prompt the user to + * install add-ons. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + * @return true if the caller should start the installs + */ + boolean onWebInstallBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); + + /** + * Called when a website wants to ask the user to install add-ons. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were requested + * @param aCount + * The number of AddonInstalls + * @return true if the caller should start the installs + */ + boolean onWebInstallRequested(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; + +[scriptable, uuid(a80b89ad-bb1a-4c43-9cb7-3ae656556f78)] +interface amIWebInstallListener2 : nsISupports +{ + /** + * Called when a non-same-origin resource attempted to initiate an install. + * Installs will have already been cancelled and cannot be restarted. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + */ + boolean onWebInstallOriginBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; + +/** + * amIWebInstallPrompt is used, if available, by the default implementation of + * amIWebInstallInfo to display a confirmation UI to the user before running + * installs. + */ +[scriptable, uuid(386906f1-4d18-45bf-bc81-5dcd68e42c3b)] +interface amIWebInstallPrompt : nsISupports +{ + /** + * Get a confirmation that the user wants to start the installs. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were requested + * @param aCount + * The number of AddonInstalls + */ + void confirm(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; diff --git a/toolkit/mozapps/webextensions/amIWebInstaller.idl b/toolkit/mozapps/webextensions/amIWebInstaller.idl new file mode 100644 index 000000000..6c5ebca67 --- /dev/null +++ b/toolkit/mozapps/webextensions/amIWebInstaller.idl @@ -0,0 +1,82 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMElement; +interface nsIVariant; +interface nsIURI; + +/** + * A callback function used to notify webpages when a requested install has + * ended. + * + * NOTE: This is *not* the same as InstallListener. + */ +[scriptable, function, uuid(bb22f5c0-3ca1-48f6-873c-54e87987700f)] +interface amIInstallCallback : nsISupports +{ + /** + * Called when an install completes or fails. + * + * @param aUrl + * The url of the add-on being installed + * @param aStatus + * 0 if the install was successful or negative if not + */ + void onInstallEnded(in AString aUrl, in int32_t aStatus); +}; + + +/** + * This interface is used to allow webpages to start installing add-ons. + */ +[scriptable, uuid(658d6c09-15e0-4688-bee8-8551030472a9)] +interface amIWebInstaller : nsISupports +{ + /** + * Checks if installation is enabled for a webpage. + * + * @param aMimetype + * The mimetype for the add-on to be installed + * @param referer + * The URL of the webpage trying to install an add-on + * @return true if installation is enabled + */ + boolean isInstallEnabled(in AString aMimetype, in nsIURI aReferer); + + /** + * Installs an array of add-ons at the request of a webpage + * + * @param aMimetype + * The mimetype for the add-ons + * @param aBrowser + * The browser installing the add-ons. + * @param aReferer + * The URI for the webpage installing the add-ons + * @param aUris + * The URIs of add-ons to be installed + * @param aHashes + * The hashes for the add-ons to be installed + * @param aNames + * The names for the add-ons to be installed + * @param aIcons + * The icons for the add-ons to be installed + * @param aCallback + * An optional callback to notify about installation success and + * failure + * @param aInstallCount + * An optional argument including the number of add-ons to install + * @return true if the installation was successfully started + */ + boolean installAddonsFromWebpage(in AString aMimetype, + in nsIDOMElement aBrowser, + in nsIURI aReferer, + [array, size_is(aInstallCount)] in wstring aUris, + [array, size_is(aInstallCount)] in wstring aHashes, + [array, size_is(aInstallCount)] in wstring aNames, + [array, size_is(aInstallCount)] in wstring aIcons, + [optional] in amIInstallCallback aCallback, + [optional] in uint32_t aInstallCount); +}; diff --git a/toolkit/mozapps/webextensions/amInstallTrigger.js b/toolkit/mozapps/webextensions/amInstallTrigger.js new file mode 100644 index 000000000..382791d32 --- /dev/null +++ b/toolkit/mozapps/webextensions/amInstallTrigger.js @@ -0,0 +1,240 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Preferences.jsm"); +Cu.import("resource://gre/modules/Log.jsm"); + +const XPINSTALL_MIMETYPE = "application/x-xpinstall"; + +const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; + + +var log = Log.repository.getLogger("AddonManager.InstallTrigger"); +log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"]; + +function CallbackObject(id, callback, urls, mediator) { + this.id = id; + this.callback = callback; + this.urls = new Set(urls); + this.callCallback = function(url, status) { + try { + this.callback(url, status); + } + catch (e) { + log.warn("InstallTrigger callback threw an exception: " + e); + } + + this.urls.delete(url); + if (this.urls.size == 0) + mediator._callbacks.delete(id); + }; +} + +function RemoteMediator(window) { + window.QueryInterface(Ci.nsIInterfaceRequestor); + let utils = window.getInterface(Ci.nsIDOMWindowUtils); + this._windowID = utils.currentInnerWindowID; + + this.mm = window + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + this.mm.addWeakMessageListener(MSG_INSTALL_CALLBACK, this); + + this._lastCallbackID = 0; + this._callbacks = new Map(); +} + +RemoteMediator.prototype = { + receiveMessage: function(message) { + if (message.name == MSG_INSTALL_CALLBACK) { + let payload = message.data; + let callbackHandler = this._callbacks.get(payload.callbackID); + if (callbackHandler) { + callbackHandler.callCallback(payload.url, payload.status); + } + } + }, + + enabled: function(url) { + let params = { + mimetype: XPINSTALL_MIMETYPE + }; + return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0]; + }, + + install: function(installs, principal, callback, window) { + let callbackID = this._addCallback(callback, installs.uris); + + installs.mimetype = XPINSTALL_MIMETYPE; + installs.triggeringPrincipal = principal; + installs.callbackID = callbackID; + + if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // When running in the main process this might be a frame inside an + // in-content UI page, walk up to find the first frame element in a chrome + // privileged document + let element = window.frameElement; + let ssm = Services.scriptSecurityManager; + while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) + element = element.ownerDocument.defaultView.frameElement; + + if (element) { + let listener = Cc["@mozilla.org/addons/integration;1"]. + getService(Ci.nsIMessageListener); + return listener.wrappedJSObject.receiveMessage({ + name: MSG_INSTALL_ADDONS, + target: element, + data: installs, + }); + } + } + + // Fall back to sending through the message manager + let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + + return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs)[0]; + }, + + _addCallback: function(callback, urls) { + if (!callback || typeof callback != "function") + return -1; + + let callbackID = this._windowID + "-" + ++this._lastCallbackID; + let callbackObject = new CallbackObject(callbackID, callback, urls, this); + this._callbacks.set(callbackID, callbackObject); + return callbackID; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]) +}; + + +function InstallTrigger() { +} + +InstallTrigger.prototype = { + // Here be magic. We've declared ourselves as providing the + // nsIDOMGlobalPropertyInitializer interface, and are registered in the + // "JavaScript-global-property" category in the XPCOM category manager. This + // means that for newly created windows, XPCOM will createinstance this + // object, and then call init, passing in the window for which we need to + // provide an instance. We then initialize ourselves and return the webidl + // version of this object using the webidl-provided _create method, which + // XPCOM will then duly expose as a property value on the window. All this + // indirection is necessary because webidl does not (yet) support statics + // (bug 863952). See bug 926712 for more details about this implementation. + init: function(window) { + this._window = window; + this._principal = window.document.nodePrincipal; + this._url = window.document.documentURIObject; + + try { + this._mediator = new RemoteMediator(window); + } catch (ex) { + // If we can't set up IPC (e.g., because this is a top-level window + // or something), then don't expose InstallTrigger. + return null; + } + + return window.InstallTriggerImpl._create(window, this); + }, + + enabled: function() { + return this._mediator.enabled(this._url.spec); + }, + + updateEnabled: function() { + return this.enabled(); + }, + + install: function(installs, callback) { + let installData = { + uris: [], + hashes: [], + names: [], + icons: [], + }; + + for (let name of Object.keys(installs)) { + let item = installs[name]; + if (typeof item === "string") { + item = { URL: item }; + } + if (!item.URL) { + throw new this._window.Error("Missing URL property for '" + name + "'"); + } + + let url = this._resolveURL(item.URL); + if (!this._checkLoadURIFromScript(url)) { + throw new this._window.Error("Insufficient permissions to install: " + url.spec); + } + + let iconUrl = null; + if (item.IconURL) { + iconUrl = this._resolveURL(item.IconURL); + if (!this._checkLoadURIFromScript(iconUrl)) { + iconUrl = null; // If page can't load the icon, just ignore it + } + } + + installData.uris.push(url.spec); + installData.hashes.push(item.Hash || null); + installData.names.push(name); + installData.icons.push(iconUrl ? iconUrl.spec : null); + } + + return this._mediator.install(installData, this._principal, callback, this._window); + }, + + startSoftwareUpdate: function(url, flags) { + let filename = Services.io.newURI(url, null, null) + .QueryInterface(Ci.nsIURL) + .filename; + let args = {}; + args[filename] = { "URL": url }; + return this.install(args); + }, + + installChrome: function(type, url, skin) { + return this.startSoftwareUpdate(url); + }, + + _resolveURL: function(url) { + return Services.io.newURI(url, null, this._url); + }, + + _checkLoadURIFromScript: function(uri) { + let secman = Services.scriptSecurityManager; + try { + secman.checkLoadURIWithPrincipal(this._principal, + uri, + secman.DISALLOW_INHERIT_PRINCIPAL); + return true; + } + catch (e) { + return false; + } + }, + + classID: Components.ID("{9df8ef2b-94da-45c9-ab9f-132eb55fddf1}"), + contractID: "@mozilla.org/addons/installtrigger;1", + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIDOMGlobalPropertyInitializer]) +}; + + + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InstallTrigger]); diff --git a/toolkit/mozapps/webextensions/amWebAPI.js b/toolkit/mozapps/webextensions/amWebAPI.js new file mode 100644 index 000000000..5ad0d23f1 --- /dev/null +++ b/toolkit/mozapps/webextensions/amWebAPI.js @@ -0,0 +1,269 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); + +const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest"; +const MSG_PROMISE_RESULT = "WebAPIPromiseResult"; +const MSG_INSTALL_EVENT = "WebAPIInstallEvent"; +const MSG_INSTALL_CLEANUP = "WebAPICleanup"; +const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest"; +const MSG_ADDON_EVENT = "WebAPIAddonEvent"; + +class APIBroker { + constructor(mm) { + this.mm = mm; + + this._promises = new Map(); + + // _installMap maps integer ids to DOM AddonInstall instances + this._installMap = new Map(); + + this.mm.addMessageListener(MSG_PROMISE_RESULT, this); + this.mm.addMessageListener(MSG_INSTALL_EVENT, this); + + this._eventListener = null; + } + + receiveMessage(message) { + let payload = message.data; + + switch (message.name) { + case MSG_PROMISE_RESULT: { + if (!this._promises.has(payload.callbackID)) { + return; + } + + let resolve = this._promises.get(payload.callbackID); + this._promises.delete(payload.callbackID); + resolve(payload); + break; + } + + case MSG_INSTALL_EVENT: { + let install = this._installMap.get(payload.id); + if (!install) { + let err = new Error(`Got install event for unknown install ${payload.id}`); + Cu.reportError(err); + return; + } + install._dispatch(payload); + break; + } + + case MSG_ADDON_EVENT: { + if (this._eventListener) { + this._eventListener(payload); + } + } + } + } + + sendRequest(type, ...args) { + return new Promise(resolve => { + let callbackID = APIBroker._nextID++; + + this._promises.set(callbackID, resolve); + this.mm.sendAsyncMessage(MSG_PROMISE_REQUEST, { type, callbackID, args }); + }); + } + + setAddonListener(callback) { + this._eventListener = callback; + if (callback) { + this.mm.addMessageListener(MSG_ADDON_EVENT, this); + this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: true}); + } else { + this.mm.removeMessageListener(MSG_ADDON_EVENT, this); + this.mm.sendAsyncMessage(MSG_ADDON_EVENT_REQ, {enabled: false}); + } + } + + sendCleanup(ids) { + this.setAddonListener(null); + this.mm.sendAsyncMessage(MSG_INSTALL_CLEANUP, { ids }); + } +} + +APIBroker._nextID = 0; + +// Base class for building classes to back content-exposed interfaces. +class APIObject { + init(window, broker, properties) { + this.window = window; + this.broker = broker; + + // Copy any provided properties onto this object, webidl bindings + // will only expose to content what should be exposed. + for (let key of Object.keys(properties)) { + this[key] = properties[key]; + } + } + + /** + * Helper to implement an asychronous method visible to content, where + * the method is implemented by sending a message to the parent process + * and then wrapping the returned object or error in an appropriate object. + * This helper method ensures that: + * - Returned Promise objects are from the content window + * - Rejected Promises have Error objects from the content window + * - Only non-internal errors are exposed to the caller + * + * @param {string} apiRequest The command to invoke in the parent process. + * @param {array} apiArgs The arguments to include with the + * request to the parent process. + * @param {function} resultConvert If provided, a function called with the + * result from the parent process as an + * argument. Used to convert the result + * into something appropriate for content. + * @returns {Promise} A Promise suitable for passing directly to content. + */ + _apiTask(apiRequest, apiArgs, resultConverter) { + let win = this.window; + let broker = this.broker; + return new win.Promise((resolve, reject) => { + Task.spawn(function*() { + let result = yield broker.sendRequest(apiRequest, ...apiArgs); + if ("reject" in result) { + let err = new win.Error(result.reject.message); + // We don't currently put any other properties onto Errors + // generated by mozAddonManager. If/when we do, they will + // need to get copied here. + reject(err); + return; + } + + let obj = result.resolve; + if (resultConverter) { + obj = resultConverter(obj); + } + resolve(obj); + }).catch(err => { + Cu.reportError(err); + reject(new win.Error("Unexpected internal error")); + }); + }); + } +} + +class Addon extends APIObject { + constructor(...args) { + super(); + this.init(...args); + } + + uninstall() { + return this._apiTask("addonUninstall", [this.id]); + } + + setEnabled(value) { + return this._apiTask("addonSetEnabled", [this.id, value]); + } +} + +class AddonInstall extends APIObject { + constructor(window, broker, properties) { + super(); + this.init(window, broker, properties); + + broker._installMap.set(properties.id, this); + } + + _dispatch(data) { + // The message for the event includes updated copies of all install + // properties. Use the usual "let webidl filter visible properties" trick. + for (let key of Object.keys(data)) { + this[key] = data[key]; + } + + let event = new this.window.Event(data.event); + this.__DOM_IMPL__.dispatchEvent(event); + } + + install() { + return this._apiTask("addonInstallDoInstall", [this.id]); + } + + cancel() { + return this._apiTask("addonInstallCancel", [this.id]); + } +} + +class WebAPI extends APIObject { + constructor() { + super(); + this.allInstalls = []; + this.listenerCount = 0; + } + + init(window) { + let mm = window + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + let broker = new APIBroker(mm); + + super.init(window, broker, {}); + + window.addEventListener("unload", event => { + this.broker.sendCleanup(this.allInstalls); + }); + } + + getAddonByID(id) { + return this._apiTask("getAddonByID", [id], addonInfo => { + if (!addonInfo) { + return null; + } + let addon = new Addon(this.window, this.broker, addonInfo); + return this.window.Addon._create(this.window, addon); + }); + } + + createInstall(options) { + return this._apiTask("createInstall", [options], installInfo => { + if (!installInfo) { + return null; + } + let install = new AddonInstall(this.window, this.broker, installInfo); + this.allInstalls.push(installInfo.id); + return this.window.AddonInstall._create(this.window, install); + }); + } + + eventListenerWasAdded(type) { + if (this.listenerCount == 0) { + this.broker.setAddonListener(data => { + let event = new this.window.AddonEvent(data.event, data); + this.__DOM_IMPL__.dispatchEvent(event); + }); + } + this.listenerCount++; + } + + eventListenerWasRemoved(type) { + this.listenerCount--; + if (this.listenerCount == 0) { + this.broker.setAddonListener(null); + } + } + + QueryInterface(iid) { + if (iid.equals(WebAPI.classID) || iid.equals(Ci.nsISupports) + || iid.equals(Ci.nsIDOMGlobalPropertyInitializer)) { + return this; + } + return Cr.NS_ERROR_NO_INTERFACE; + } +} + +WebAPI.prototype.classID = Components.ID("{8866d8e3-4ea5-48b7-a891-13ba0ac15235}"); +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebAPI]); diff --git a/toolkit/mozapps/webextensions/amWebInstallListener.js b/toolkit/mozapps/webextensions/amWebInstallListener.js new file mode 100644 index 000000000..0bcc345e8 --- /dev/null +++ b/toolkit/mozapps/webextensions/amWebInstallListener.js @@ -0,0 +1,348 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This is a default implementation of amIWebInstallListener that should work + * for most applications but can be overriden. It notifies the observer service + * about blocked installs. For normal installs it pops up an install + * confirmation when all the add-ons have been downloaded. + */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Preferences.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "PromptUtils", "resource://gre/modules/SharedPromptUtils.jsm"); + +const URI_XPINSTALL_DIALOG = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; + +// Installation can begin from any of these states +const READY_STATES = [ + AddonManager.STATE_AVAILABLE, + AddonManager.STATE_DOWNLOAD_FAILED, + AddonManager.STATE_INSTALL_FAILED, + AddonManager.STATE_CANCELLED +]; + +Cu.import("resource://gre/modules/Log.jsm"); +const LOGGER_ID = "addons.weblistener"; + +// Create a new logger for use by the Addons Web Listener +// (Requires AddonManager.jsm) +var logger = Log.repository.getLogger(LOGGER_ID); + +function notifyObservers(aTopic, aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, aTopic, null); +} + +/** + * Creates a new installer to monitor downloads and prompt to install when + * ready + * + * @param aBrowser + * The browser that started the installations + * @param aUrl + * The URL that started the installations + * @param aInstalls + * An array of AddonInstalls + */ +function Installer(aBrowser, aUrl, aInstalls) { + this.browser = aBrowser; + this.url = aUrl; + this.downloads = aInstalls; + this.installed = []; + + notifyObservers("addon-install-started", aBrowser, aUrl, aInstalls); + + for (let install of aInstalls) { + install.addListener(this); + + // Start downloading if it hasn't already begun + if (READY_STATES.indexOf(install.state) != -1) + install.install(); + } + + this.checkAllDownloaded(); +} + +Installer.prototype = { + browser: null, + downloads: null, + installed: null, + isDownloading: true, + + /** + * Checks if all downloads are now complete and if so prompts to install. + */ + checkAllDownloaded: function() { + // Prevent re-entrancy caused by the confirmation dialog cancelling unwanted + // installs. + if (!this.isDownloading) + return; + + var failed = []; + var installs = []; + + for (let install of this.downloads) { + switch (install.state) { + case AddonManager.STATE_AVAILABLE: + case AddonManager.STATE_DOWNLOADING: + // Exit early if any add-ons haven't started downloading yet or are + // still downloading + return; + case AddonManager.STATE_DOWNLOAD_FAILED: + failed.push(install); + break; + case AddonManager.STATE_DOWNLOADED: + // App disabled items are not compatible and so fail to install + if (install.addon.appDisabled) + failed.push(install); + else + installs.push(install); + + if (install.linkedInstalls) { + for (let linkedInstall of install.linkedInstalls) { + linkedInstall.addListener(this); + // Corrupt or incompatible items fail to install + if (linkedInstall.state == AddonManager.STATE_DOWNLOAD_FAILED || linkedInstall.addon.appDisabled) + failed.push(linkedInstall); + else + installs.push(linkedInstall); + } + } + break; + case AddonManager.STATE_CANCELLED: + // Just ignore cancelled downloads + break; + default: + logger.warn("Download of " + install.sourceURI.spec + " in unexpected state " + + install.state); + } + } + + this.isDownloading = false; + this.downloads = installs; + + if (failed.length > 0) { + // Stop listening and cancel any installs that are failed because of + // compatibility reasons. + for (let install of failed) { + if (install.state == AddonManager.STATE_DOWNLOADED) { + install.removeListener(this); + install.cancel(); + } + } + notifyObservers("addon-install-failed", this.browser, this.url, failed); + } + + // If none of the downloads were successful then exit early + if (this.downloads.length == 0) + return; + + // Check for a custom installation prompt that may be provided by the + // applicaton + if ("@mozilla.org/addons/web-install-prompt;1" in Cc) { + try { + let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"]. + getService(Ci.amIWebInstallPrompt); + prompt.confirm(this.browser, this.url, this.downloads, this.downloads.length); + return; + } + catch (e) {} + } + + if (Preferences.get("xpinstall.customConfirmationUI", false)) { + notifyObservers("addon-install-confirmation", this.browser, this.url, this.downloads); + return; + } + + let args = {}; + args.url = this.url; + args.installs = this.downloads; + args.wrappedJSObject = args; + + try { + Cc["@mozilla.org/base/telemetry;1"]. + getService(Ci.nsITelemetry). + getHistogramById("SECURITY_UI"). + add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL); + let parentWindow = null; + if (this.browser) { + parentWindow = this.browser.ownerDocument.defaultView; + PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", this.browser); + } + Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG, + null, "chrome,modal,centerscreen", args); + } catch (e) { + logger.warn("Exception showing install confirmation dialog", e); + for (let install of this.downloads) { + install.removeListener(this); + // Cancel the installs, as currently there is no way to make them fail + // from here. + install.cancel(); + } + notifyObservers("addon-install-cancelled", this.browser, this.url, + this.downloads); + } + }, + + /** + * Checks if all installs are now complete and if so notifies observers. + */ + checkAllInstalled: function() { + var failed = []; + + for (let install of this.downloads) { + switch (install.state) { + case AddonManager.STATE_DOWNLOADED: + case AddonManager.STATE_INSTALLING: + // Exit early if any add-ons haven't started installing yet or are + // still installing + return; + case AddonManager.STATE_INSTALL_FAILED: + failed.push(install); + break; + } + } + + this.downloads = null; + + if (failed.length > 0) + notifyObservers("addon-install-failed", this.browser, this.url, failed); + + if (this.installed.length > 0) + notifyObservers("addon-install-complete", this.browser, this.url, this.installed); + this.installed = null; + }, + + onDownloadCancelled: function(aInstall) { + aInstall.removeListener(this); + this.checkAllDownloaded(); + }, + + onDownloadFailed: function(aInstall) { + aInstall.removeListener(this); + this.checkAllDownloaded(); + }, + + onDownloadEnded: function(aInstall) { + this.checkAllDownloaded(); + return false; + }, + + onInstallCancelled: function(aInstall) { + aInstall.removeListener(this); + this.checkAllInstalled(); + }, + + onInstallFailed: function(aInstall) { + aInstall.removeListener(this); + this.checkAllInstalled(); + }, + + onInstallEnded: function(aInstall) { + aInstall.removeListener(this); + this.installed.push(aInstall); + + // If installing a theme that is disabled and can be enabled then enable it + if (aInstall.addon.type == "theme" && + aInstall.addon.userDisabled == true && + aInstall.addon.appDisabled == false) { + aInstall.addon.userDisabled = false; + } + + this.checkAllInstalled(); + } +}; + +function extWebInstallListener() { +} + +extWebInstallListener.prototype = { + /** + * @see amIWebInstallListener.idl + */ + onWebInstallDisabled: function(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-disabled", null); + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallOriginBlocked: function(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + install: function() { + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-origin-blocked", null); + + return false; + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallBlocked: function(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + install: function() { + new Installer(this.browser, this.originatingURI, this.installs); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-blocked", null); + + return false; + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallRequested: function(aBrowser, aUri, aInstalls) { + new Installer(aBrowser, aUri, aInstalls); + + // We start the installs ourself + return false; + }, + + classDescription: "XPI Install Handler", + contractID: "@mozilla.org/addons/web-install-listener;1", + classID: Components.ID("{0f38e086-89a3-40a5-8ffc-9b694de1d04a}"), + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallListener, + Ci.amIWebInstallListener2]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([extWebInstallListener]); diff --git a/toolkit/mozapps/webextensions/content/OpenH264-license.txt b/toolkit/mozapps/webextensions/content/OpenH264-license.txt new file mode 100644 index 000000000..ad37989b8 --- /dev/null +++ b/toolkit/mozapps/webextensions/content/OpenH264-license.txt @@ -0,0 +1,59 @@ +------------------------------------------------------- +About The Cisco-Provided Binary of OpenH264 Video Codec +------------------------------------------------------- + +Cisco provides this program under the terms of the BSD license. + +Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. + +As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. + +For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary + +A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org + +----------- +BSD License +----------- + +Copyright © 2014 Cisco Systems, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------- +AVC/H.264 Patent Portfolio License Notice +----------------------------------------- + +The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: + +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM + +Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla + +--------------------------------------------- +AVC/H.264 Patent Portfolio License Conditions +--------------------------------------------- + +In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met: + +1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device; + +2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary; + +3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text: + + "OpenH264 Video Codec provided by Cisco Systems, Inc." + +4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. + + + + v1.0 diff --git a/toolkit/mozapps/webextensions/content/about.js b/toolkit/mozapps/webextensions/content/about.js new file mode 100644 index 000000000..4f8fb353e --- /dev/null +++ b/toolkit/mozapps/webextensions/content/about.js @@ -0,0 +1,103 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/* import-globals-from ../../../content/contentAreaUtils.js */ + +var Cu = Components.utils; +Cu.import("resource://gre/modules/AddonManager.jsm"); + +function init() { + var addon = window.arguments[0]; + var extensionsStrings = document.getElementById("extensionsStrings"); + + document.documentElement.setAttribute("addontype", addon.type); + + var iconURL = AddonManager.getPreferredIconURL(addon, 48, window); + if (iconURL) { + var extensionIcon = document.getElementById("extensionIcon"); + extensionIcon.src = iconURL; + } + + document.title = extensionsStrings.getFormattedString("aboutWindowTitle", [addon.name]); + var extensionName = document.getElementById("extensionName"); + extensionName.textContent = addon.name; + + var extensionVersion = document.getElementById("extensionVersion"); + if (addon.version) + extensionVersion.setAttribute("value", extensionsStrings.getFormattedString("aboutWindowVersionString", [addon.version])); + else + extensionVersion.hidden = true; + + var extensionDescription = document.getElementById("extensionDescription"); + if (addon.description) + extensionDescription.textContent = addon.description; + else + extensionDescription.hidden = true; + + var numDetails = 0; + + var extensionCreator = document.getElementById("extensionCreator"); + if (addon.creator) { + extensionCreator.setAttribute("value", addon.creator); + numDetails++; + } else { + extensionCreator.hidden = true; + var extensionCreatorLabel = document.getElementById("extensionCreatorLabel"); + extensionCreatorLabel.hidden = true; + } + + var extensionHomepage = document.getElementById("extensionHomepage"); + var homepageURL = addon.homepageURL; + if (homepageURL) { + extensionHomepage.setAttribute("homepageURL", homepageURL); + extensionHomepage.setAttribute("tooltiptext", homepageURL); + numDetails++; + } else { + extensionHomepage.hidden = true; + } + + numDetails += appendToList("extensionDevelopers", "developersBox", addon.developers); + numDetails += appendToList("extensionTranslators", "translatorsBox", addon.translators); + numDetails += appendToList("extensionContributors", "contributorsBox", addon.contributors); + + if (numDetails == 0) { + var groove = document.getElementById("groove"); + groove.hidden = true; + var extensionDetailsBox = document.getElementById("extensionDetailsBox"); + extensionDetailsBox.hidden = true; + } + + var acceptButton = document.documentElement.getButton("accept"); + acceptButton.label = extensionsStrings.getString("aboutWindowCloseButton"); + + setTimeout(sizeToContent, 0); +} + +function appendToList(aHeaderId, aNodeId, aItems) { + var header = document.getElementById(aHeaderId); + var node = document.getElementById(aNodeId); + + if (!aItems || aItems.length == 0) { + header.hidden = true; + return 0; + } + + for (let currentItem of aItems) { + var label = document.createElement("label"); + label.textContent = currentItem; + label.setAttribute("class", "contributor"); + node.appendChild(label); + } + + return aItems.length; +} + +function loadHomepage(aEvent) { + window.close(); + openURL(aEvent.target.getAttribute("homepageURL")); +} diff --git a/toolkit/mozapps/webextensions/content/about.xul b/toolkit/mozapps/webextensions/content/about.xul new file mode 100644 index 000000000..6effcf37a --- /dev/null +++ b/toolkit/mozapps/webextensions/content/about.xul @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + +

Test page for the discovery pane

+

Direct install

+

JS install

+ + diff --git a/toolkit/mozapps/webextensions/test/browser/head.js b/toolkit/mozapps/webextensions/test/browser/head.js new file mode 100644 index 000000000..5a749099d --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/head.js @@ -0,0 +1,1468 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +/* globals end_test*/ + +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +var tmp = {}; +Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp); +Components.utils.import("resource://gre/modules/Log.jsm", tmp); +var AddonManager = tmp.AddonManager; +var AddonManagerPrivate = tmp.AddonManagerPrivate; +var Log = tmp.Log; + +var pathParts = gTestPath.split("/"); +// Drop the test filename +pathParts.splice(pathParts.length - 1, pathParts.length); + +var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]); + +// Drop the UI type +if (gTestInWindow) { + pathParts.splice(pathParts.length - 1, pathParts.length); +} + +const RELATIVE_DIR = pathParts.slice(4).join("/") + "/"; + +const TESTROOT = "http://example.com/" + RELATIVE_DIR; +const SECURE_TESTROOT = "https://example.com/" + RELATIVE_DIR; +const TESTROOT2 = "http://example.org/" + RELATIVE_DIR; +const SECURE_TESTROOT2 = "https://example.org/" + RELATIVE_DIR; +const CHROMEROOT = pathParts.join("/") + "/"; +const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; +const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; +const PREF_XPI_ENABLED = "xpinstall.enabled"; +const PREF_UPDATEURL = "extensions.update.url"; +const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; +const PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI = "xpinstall.customConfirmationUI"; +const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory"; + +const MANAGER_URI = "about:addons"; +const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults"; +const PREF_STRICT_COMPAT = "extensions.strictCompatibility"; + +var PREF_CHECK_COMPATIBILITY; +(function() { + var channel = "default"; + try { + channel = Services.prefs.getCharPref("app.update.channel"); + } catch (e) { } + if (channel != "aurora" && + channel != "beta" && + channel != "release" && + channel != "esr") { + var version = "nightly"; + } else { + version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1"); + } + PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version; +})(); + +var gPendingTests = []; +var gTestsRun = 0; +var gTestStart = null; + +var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window); + +var gRestorePrefs = [{name: PREF_LOGGING_ENABLED}, + {name: PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI}, + {name: "extensions.webservice.discoverURL"}, + {name: "extensions.update.url"}, + {name: "extensions.update.background.url"}, + {name: "extensions.update.enabled"}, + {name: "extensions.update.autoUpdateDefault"}, + {name: "extensions.getAddons.get.url"}, + {name: "extensions.getAddons.getWithPerformance.url"}, + {name: "extensions.getAddons.search.browseURL"}, + {name: "extensions.getAddons.search.url"}, + {name: "extensions.getAddons.cache.enabled"}, + {name: "devtools.chrome.enabled"}, + {name: PREF_SEARCH_MAXRESULTS}, + {name: PREF_STRICT_COMPAT}, + {name: PREF_CHECK_COMPATIBILITY}]; + +for (let pref of gRestorePrefs) { + if (!Services.prefs.prefHasUserValue(pref.name)) { + pref.type = "clear"; + continue; + } + pref.type = Services.prefs.getPrefType(pref.name); + if (pref.type == Services.prefs.PREF_BOOL) + pref.value = Services.prefs.getBoolPref(pref.name); + else if (pref.type == Services.prefs.PREF_INT) + pref.value = Services.prefs.getIntPref(pref.name); + else if (pref.type == Services.prefs.PREF_STRING) + pref.value = Services.prefs.getCharPref(pref.name); +} + +// Turn logging on for all tests +Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); + +Services.prefs.setBoolPref(PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI, false); + +// Helper to register test failures and close windows if any are left open +function checkOpenWindows(aWindowID) { + let windows = Services.wm.getEnumerator(aWindowID); + let found = false; + while (windows.hasMoreElements()) { + let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); + if (!win.closed) { + found = true; + win.close(); + } + } + if (found) + ok(false, "Found unexpected " + aWindowID + " window still open"); +} + +// Tools to disable and re-enable the background update and blocklist timers +// so that tests can protect themselves from unwanted timer events. +var gCatMan = Components.classes["@mozilla.org/categorymanager;1"] + .getService(Components.interfaces.nsICategoryManager); +// Default values from toolkit/mozapps/extensions/extensions.manifest, but disable*UpdateTimer() +// records the actual value so we can put it back in enable*UpdateTimer() +var backgroundUpdateConfig = "@mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400"; +var blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400"; + +var UTIMER = "update-timer"; +var AMANAGER = "addonManager"; +var BLOCKLIST = "nsBlocklistService"; + +function disableBackgroundUpdateTimer() { + info("Disabling " + UTIMER + " " + AMANAGER); + backgroundUpdateConfig = gCatMan.getCategoryEntry(UTIMER, AMANAGER); + gCatMan.deleteCategoryEntry(UTIMER, AMANAGER, true); +} + +function enableBackgroundUpdateTimer() { + info("Enabling " + UTIMER + " " + AMANAGER); + gCatMan.addCategoryEntry(UTIMER, AMANAGER, backgroundUpdateConfig, false, true); +} + +function disableBlocklistUpdateTimer() { + info("Disabling " + UTIMER + " " + BLOCKLIST); + blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST); + gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true); +} + +function enableBlocklistUpdateTimer() { + info("Enabling " + UTIMER + " " + BLOCKLIST); + gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true); +} + +registerCleanupFunction(function() { + // Restore prefs + for (let pref of gRestorePrefs) { + if (pref.type == "clear") + Services.prefs.clearUserPref(pref.name); + else if (pref.type == Services.prefs.PREF_BOOL) + Services.prefs.setBoolPref(pref.name, pref.value); + else if (pref.type == Services.prefs.PREF_INT) + Services.prefs.setIntPref(pref.name, pref.value); + else if (pref.type == Services.prefs.PREF_STRING) + Services.prefs.setCharPref(pref.name, pref.value); + } + + // Throw an error if the add-ons manager window is open anywhere + checkOpenWindows("Addons:Manager"); + checkOpenWindows("Addons:Compatibility"); + checkOpenWindows("Addons:Install"); + + return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve)) + .then(aInstalls => { + for (let install of aInstalls) { + if (install instanceof MockInstall) + continue; + + ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state); + install.cancel(); + } + }); +}); + +function log_exceptions(aCallback, ...aArgs) { + try { + return aCallback.apply(null, aArgs); + } + catch (e) { + info("Exception thrown: " + e); + throw e; + } +} + +function log_callback(aPromise, aCallback) { + aPromise.then(aCallback) + .then(null, e => info("Exception thrown: " + e)); + return aPromise; +} + +function add_test(test) { + gPendingTests.push(test); +} + +function run_next_test() { + // Make sure we're not calling run_next_test from inside an add_task() test + // We're inside the browser_test.js 'testScope' here + if (this.__tasks) { + throw new Error("run_next_test() called from an add_task() test function. " + + "run_next_test() should not be called from inside add_task() " + + "under any circumstances!"); + } + if (gTestsRun > 0) + info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms"); + + if (gPendingTests.length == 0) { + executeSoon(end_test); + return; + } + + gTestsRun++; + var test = gPendingTests.shift(); + if (test.name) + info("Running test " + gTestsRun + " (" + test.name + ")"); + else + info("Running test " + gTestsRun); + + gTestStart = Date.now(); + executeSoon(() => log_exceptions(test)); +} + +var get_tooltip_info = Task.async(function*(addon) { + let managerWindow = addon.ownerDocument.defaultView; + + // The popup code uses a triggering event's target to set the + // document.tooltipNode property. + let nameNode = addon.ownerDocument.getAnonymousElementByAttribute(addon, "anonid", "name"); + let event = new managerWindow.CustomEvent("TriggerEvent"); + nameNode.dispatchEvent(event); + + let tooltip = managerWindow.document.getElementById("addonitem-tooltip"); + + let promise = BrowserTestUtils.waitForEvent(tooltip, "popupshown"); + tooltip.openPopup(nameNode, "after_start", 0, 0, false, false, event); + yield promise; + + let tiptext = tooltip.label; + + promise = BrowserTestUtils.waitForEvent(tooltip, "popuphidden"); + tooltip.hidePopup(); + yield promise; + + let expectedName = addon.getAttribute("name"); + ok(tiptext.substring(0, expectedName.length), expectedName, + "Tooltip should always start with the expected name"); + + if (expectedName.length == tiptext.length) { + return { + name: tiptext, + version: undefined + }; + } + return { + name: tiptext.substring(0, expectedName.length), + version: tiptext.substring(expectedName.length + 1) + }; +}); + +function get_addon_file_url(aFilename) { + try { + var cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIChromeRegistry); + var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename)); + return fileurl.QueryInterface(Ci.nsIFileURL); + } catch (ex) { + var jar = getJar(CHROMEROOT + "addons/" + aFilename); + var tmpDir = extractJarToTmp(jar); + tmpDir.append(aFilename); + + return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL); + } +} + +function get_current_view(aManager) { + let view = aManager.document.getElementById("view-port").selectedPanel; + if (view.id == "headered-views") { + view = aManager.document.getElementById("headered-views-content").selectedPanel; + } + is(view, aManager.gViewController.displayedView, "view controller is tracking the displayed view correctly"); + return view; +} + +function get_test_items_in_list(aManager) { + var tests = "@tests.mozilla.org"; + + let view = get_current_view(aManager); + let listid = view.id == "search-view" ? "search-list" : "addon-list"; + let item = aManager.document.getElementById(listid).firstChild; + let items = []; + + while (item) { + if (item.localName != "richlistitem") { + item = item.nextSibling; + continue; + } + + if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests) + items.push(item); + item = item.nextSibling; + } + + return items; +} + +function check_all_in_list(aManager, aIds, aIgnoreExtras) { + var doc = aManager.document; + var view = get_current_view(aManager); + var listid = view.id == "search-view" ? "search-list" : "addon-list"; + var list = doc.getElementById(listid); + + var inlist = []; + var node = list.firstChild; + while (node) { + if (node.value) + inlist.push(node.value); + node = node.nextSibling; + } + + for (let id of aIds) { + if (inlist.indexOf(id) == -1) + ok(false, "Should find " + id + " in the list"); + } + + if (aIgnoreExtras) + return; + + for (let inlistItem of inlist) { + if (aIds.indexOf(inlistItem) == -1) + ok(false, "Shouldn't have seen " + inlistItem + " in the list"); + } +} + +function get_addon_element(aManager, aId) { + var doc = aManager.document; + var view = get_current_view(aManager); + var listid = "addon-list"; + if (view.id == "search-view") + listid = "search-list"; + else if (view.id == "updates-view") + listid = "updates-list"; + var list = doc.getElementById(listid); + + var node = list.firstChild; + while (node) { + if (node.value == aId) + return node; + node = node.nextSibling; + } + return null; +} + +function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) { + requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); + + if (!aForceWait && !aManagerWindow.gViewController.isLoading) { + log_exceptions(aCallback, aManagerWindow); + return; + } + + aManagerWindow.document.addEventListener("ViewChanged", function() { + aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false); + log_exceptions(aCallback, aManagerWindow); + }, false); +} + +function wait_for_manager_load(aManagerWindow, aCallback) { + if (!aManagerWindow.gIsInitializing) { + log_exceptions(aCallback, aManagerWindow); + return; + } + + info("Waiting for initialization"); + aManagerWindow.document.addEventListener("Initialized", function() { + aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false); + log_exceptions(aCallback, aManagerWindow); + }, false); +} + +function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) { + let p = new Promise((resolve, reject) => { + + function setup_manager(aManagerWindow) { + if (aLoadCallback) + log_exceptions(aLoadCallback, aManagerWindow); + + if (aView) + aManagerWindow.loadView(aView); + + ok(aManagerWindow != null, "Should have an add-ons manager window"); + is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI"); + + waitForFocus(function() { + info("window has focus, waiting for manager load"); + wait_for_manager_load(aManagerWindow, function() { + info("Manager waiting for view load"); + wait_for_view_load(aManagerWindow, function() { + resolve(aManagerWindow); + }, null, aLongerTimeout); + }); + }, aManagerWindow); + } + + if (gUseInContentUI) { + info("Loading manager window in tab"); + Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.removeObserver(arguments.callee, aTopic); + if (aSubject.location.href != MANAGER_URI) { + info("Ignoring load event for " + aSubject.location.href); + return; + } + setup_manager(aSubject); + }, "EM-loaded", false); + + gBrowser.selectedTab = gBrowser.addTab(); + switchToTabHavingURI(MANAGER_URI, true); + } else { + info("Loading manager window in dialog"); + Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.removeObserver(arguments.callee, aTopic); + setup_manager(aSubject); + }, "EM-loaded", false); + + openDialog(MANAGER_URI); + } + }); + + // The promise resolves with the manager window, so it is passed to the callback + return log_callback(p, aCallback); +} + +function close_manager(aManagerWindow, aCallback, aLongerTimeout) { + let p = new Promise((resolve, reject) => { + requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); + + ok(aManagerWindow != null, "Should have an add-ons manager window to close"); + is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI"); + + aManagerWindow.addEventListener("unload", function() { + try { + dump("Manager window unload handler\n"); + this.removeEventListener("unload", arguments.callee, false); + resolve(); + } catch (e) { + reject(e); + } + }, false); + }); + + info("Telling manager window to close"); + aManagerWindow.close(); + info("Manager window close() call returned"); + + return log_callback(p, aCallback); +} + +function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) { + if (!aManagerWindow) { + return open_manager(aView, aCallback, aLoadCallback); + } + + return close_manager(aManagerWindow) + .then(() => open_manager(aView, aCallback, aLoadCallback)); +} + +function wait_for_window_open(aCallback) { + Services.wm.addListener({ + onOpenWindow: function(aWindow) { + Services.wm.removeListener(this); + + let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + domwindow.addEventListener("load", function() { + domwindow.removeEventListener("load", arguments.callee, false); + executeSoon(function() { + aCallback(domwindow); + }); + }, false); + }, + + onCloseWindow: function(aWindow) { + }, + + onWindowTitleChange: function(aWindow, aTitle) { + } + }); +} + +function get_string(aName, ...aArgs) { + var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); + if (aArgs.length == 0) + return bundle.GetStringFromName(aName); + return bundle.formatStringFromName(aName, aArgs, aArgs.length); +} + +function formatDate(aDate) { + const locale = Cc["@mozilla.org/chrome/chrome-registry;1"] + .getService(Ci.nsIXULChromeRegistry) + .getSelectedLocale("global", true); + const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' }; + return aDate.toLocaleDateString(locale, dtOptions); +} + +function is_hidden(aElement) { + var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, ""); + if (style.display == "none") + return true; + if (style.visibility != "visible") + return true; + + // Hiding a parent element will hide all its children + if (aElement.parentNode != aElement.ownerDocument) + return is_hidden(aElement.parentNode); + + return false; +} + +function is_element_visible(aElement, aMsg) { + isnot(aElement, null, "Element should not be null, when checking visibility"); + ok(!is_hidden(aElement), aMsg || (aElement + " should be visible")); +} + +function is_element_hidden(aElement, aMsg) { + isnot(aElement, null, "Element should not be null, when checking visibility"); + ok(is_hidden(aElement), aMsg || (aElement + " should be hidden")); +} + +function promiseAddonByID(aId) { + return new Promise(resolve => { + AddonManager.getAddonByID(aId, resolve); + }); +} + +function promiseAddonsByIDs(aIDs) { + return new Promise(resolve => { + AddonManager.getAddonsByIDs(aIDs, resolve); + }); +} +/** + * Install an add-on and call a callback when complete. + * + * The callback will receive the Addon for the installed add-on. + */ +function install_addon(path, cb, pathPrefix=TESTROOT) { + let p = new Promise((resolve, reject) => { + AddonManager.getInstallForURL(pathPrefix + path, (install) => { + install.addListener({ + onInstallEnded: () => resolve(install.addon), + }); + + install.install(); + }, "application/x-xpinstall"); + }); + + return log_callback(p, cb); +} + +function CategoryUtilities(aManagerWindow) { + this.window = aManagerWindow; + + var self = this; + this.window.addEventListener("unload", function() { + self.window.removeEventListener("unload", arguments.callee, false); + self.window = null; + }, false); +} + +CategoryUtilities.prototype = { + window: null, + + get selectedCategory() { + isnot(this.window, null, "Should not get selected category when manager window is not loaded"); + var selectedItem = this.window.document.getElementById("categories").selectedItem; + isnot(selectedItem, null, "A category should be selected"); + var view = this.window.gViewController.parseViewId(selectedItem.value); + return (view.type == "list") ? view.param : view.type; + }, + + get: function(aCategoryType, aAllowMissing) { + isnot(this.window, null, "Should not get category when manager window is not loaded"); + var categories = this.window.document.getElementById("categories"); + + var viewId = "addons://list/" + aCategoryType; + var items = categories.getElementsByAttribute("value", viewId); + if (items.length) + return items[0]; + + viewId = "addons://" + aCategoryType + "/"; + items = categories.getElementsByAttribute("value", viewId); + if (items.length) + return items[0]; + + if (!aAllowMissing) + ok(false, "Should have found a category with type " + aCategoryType); + return null; + }, + + getViewId: function(aCategoryType) { + isnot(this.window, null, "Should not get view id when manager window is not loaded"); + return this.get(aCategoryType).value; + }, + + isVisible: function(aCategory) { + isnot(this.window, null, "Should not check visible state when manager window is not loaded"); + if (aCategory.hasAttribute("disabled") && + aCategory.getAttribute("disabled") == "true") + return false; + + return !is_hidden(aCategory); + }, + + isTypeVisible: function(aCategoryType) { + return this.isVisible(this.get(aCategoryType)); + }, + + open: function(aCategory, aCallback) { + + isnot(this.window, null, "Should not open category when manager window is not loaded"); + ok(this.isVisible(aCategory), "Category should be visible if attempting to open it"); + + EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window); + let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve)); + + return log_callback(p, aCallback); + }, + + openType: function(aCategoryType, aCallback) { + return this.open(this.get(aCategoryType), aCallback); + } +} + +function CertOverrideListener(host, bits) { + this.host = host; + this.bits = bits; +} + +CertOverrideListener.prototype = { + host: null, + bits: null, + + getInterface: function (aIID) { + return this.QueryInterface(aIID); + }, + + QueryInterface: function(aIID) { + if (aIID.equals(Ci.nsIBadCertListener2) || + aIID.equals(Ci.nsIInterfaceRequestor) || + aIID.equals(Ci.nsISupports)) + return this; + + throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); + }, + + notifyCertProblem: function (socketInfo, sslStatus, targetHost) { + var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus) + .serverCert; + var cos = Cc["@mozilla.org/security/certoverride;1"]. + getService(Ci.nsICertOverrideService); + cos.rememberValidityOverride(this.host, -1, cert, this.bits, false); + return true; + } +} + +// Add overrides for the bad certificates +function addCertOverride(host, bits) { + var req = new XMLHttpRequest(); + try { + req.open("GET", "https://" + host + "/", false); + req.channel.notificationCallbacks = new CertOverrideListener(host, bits); + req.send(null); + } + catch (e) { + // This request will fail since the SSL server is not trusted yet + } +} + +/** *** Mock Provider *****/ + +function MockProvider(aUseAsyncCallbacks, aTypes) { + this.addons = []; + this.installs = []; + this.callbackTimers = []; + this.timerLocations = new Map(); + this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks; + this.types = (aTypes === undefined) ? [{ + id: "extension", + name: "Extensions", + uiPriority: 4000, + flags: AddonManager.TYPE_UI_VIEW_LIST | + AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL, + }] : aTypes; + + var self = this; + registerCleanupFunction(function() { + if (self.started) + self.unregister(); + }); + + this.register(); +} + +MockProvider.prototype = { + addons: null, + installs: null, + started: null, + apiDelay: 10, + callbackTimers: null, + timerLocations: null, + useAsyncCallbacks: null, + types: null, + + /** *** Utility functions *****/ + + /** + * Register this provider with the AddonManager + */ + register: function MP_register() { + info("Registering mock add-on provider"); + AddonManagerPrivate.registerProvider(this, this.types); + }, + + /** + * Unregister this provider with the AddonManager + */ + unregister: function MP_unregister() { + info("Unregistering mock add-on provider"); + AddonManagerPrivate.unregisterProvider(this); + }, + + /** + * Adds an add-on to the list of add-ons that this provider exposes to the + * AddonManager, dispatching appropriate events in the process. + * + * @param aAddon + * The add-on to add + */ + addAddon: function MP_addAddon(aAddon) { + var oldAddons = this.addons.filter(aOldAddon => aOldAddon.id == aAddon.id); + var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null; + + this.addons = this.addons.filter(aOldAddon => aOldAddon.id != aAddon.id); + + this.addons.push(aAddon); + aAddon._provider = this; + + if (!this.started) + return; + + let requiresRestart = (aAddon.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_INSTALL) != 0; + AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon, + oldAddon, requiresRestart) + }, + + /** + * Removes an add-on from the list of add-ons that this provider exposes to + * the AddonManager, dispatching the onUninstalled event in the process. + * + * @param aAddon + * The add-on to add + */ + removeAddon: function MP_removeAddon(aAddon) { + var pos = this.addons.indexOf(aAddon); + if (pos == -1) { + ok(false, "Tried to remove an add-on that wasn't registered with the mock provider"); + return; + } + + this.addons.splice(pos, 1); + + if (!this.started) + return; + + AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon); + }, + + /** + * Adds an add-on install to the list of installs that this provider exposes + * to the AddonManager, dispatching appropriate events in the process. + * + * @param aInstall + * The add-on install to add + */ + addInstall: function MP_addInstall(aInstall) { + this.installs.push(aInstall); + aInstall._provider = this; + + if (!this.started) + return; + + aInstall.callListeners("onNewInstall"); + }, + + removeInstall: function MP_removeInstall(aInstall) { + var pos = this.installs.indexOf(aInstall); + if (pos == -1) { + ok(false, "Tried to remove an install that wasn't registered with the mock provider"); + return; + } + + this.installs.splice(pos, 1); + }, + + /** + * Creates a set of mock add-on objects and adds them to the list of add-ons + * managed by this provider. + * + * @param aAddonProperties + * An array of objects containing properties describing the add-ons + * @return Array of the new MockAddons + */ + createAddons: function MP_createAddons(aAddonProperties) { + var newAddons = []; + for (let addonProp of aAddonProperties) { + let addon = new MockAddon(addonProp.id); + for (let prop in addonProp) { + if (prop == "id") + continue; + if (prop == "applyBackgroundUpdates") { + addon._applyBackgroundUpdates = addonProp[prop]; + continue; + } + if (prop == "appDisabled") { + addon._appDisabled = addonProp[prop]; + continue; + } + addon[prop] = addonProp[prop]; + } + if (!addon.optionsType && !!addon.optionsURL) + addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG; + + // Make sure the active state matches the passed in properties + addon.isActive = addon.shouldBeActive; + + this.addAddon(addon); + newAddons.push(addon); + } + + return newAddons; + }, + + /** + * Creates a set of mock add-on install objects and adds them to the list + * of installs managed by this provider. + * + * @param aInstallProperties + * An array of objects containing properties describing the installs + * @return Array of the new MockInstalls + */ + createInstalls: function MP_createInstalls(aInstallProperties) { + var newInstalls = []; + for (let installProp of aInstallProperties) { + let install = new MockInstall(installProp.name || null, + installProp.type || null, + null); + for (let prop in installProp) { + switch (prop) { + case "name": + case "type": + break; + case "sourceURI": + install[prop] = NetUtil.newURI(installProp[prop]); + break; + default: + install[prop] = installProp[prop]; + } + } + this.addInstall(install); + newInstalls.push(install); + } + + return newInstalls; + }, + + /** *** AddonProvider implementation *****/ + + /** + * Called to initialize the provider. + */ + startup: function MP_startup() { + this.started = true; + }, + + /** + * Called when the provider should shutdown. + */ + shutdown: function MP_shutdown() { + if (this.callbackTimers.length) { + info("MockProvider: pending callbacks at shutdown(): calling immediately"); + } + while (this.callbackTimers.length > 0) { + // When we notify the callback timer, it removes itself from our array + let timer = this.callbackTimers[0]; + try { + let setAt = this.timerLocations.get(timer); + info("Notifying timer set at " + (setAt || "unknown location")); + timer.callback.notify(timer); + timer.cancel(); + } catch (e) { + info("Timer notify failed: " + e); + } + } + this.callbackTimers = []; + this.timerLocations = null; + + this.started = false; + }, + + /** + * Called to get an Addon with a particular ID. + * + * @param aId + * The ID of the add-on to retrieve + * @param aCallback + * A callback to pass the Addon to + */ + getAddonByID: function MP_getAddon(aId, aCallback) { + for (let addon of this.addons) { + if (addon.id == aId) { + this._delayCallback(aCallback, addon); + return; + } + } + + aCallback(null); + }, + + /** + * Called to get Addons of a particular type. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types. + * @param callback + * A callback to pass an array of Addons to + */ + getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) { + var addons = this.addons.filter(function(aAddon) { + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) + return false; + return true; + }); + this._delayCallback(aCallback, addons); + }, + + /** + * Called to get Addons that have pending operations. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types + * @param aCallback + * A callback to pass an array of Addons to + */ + getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) { + var addons = this.addons.filter(function(aAddon) { + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) + return false; + return aAddon.pendingOperations != 0; + }); + this._delayCallback(aCallback, addons); + }, + + /** + * Called to get the current AddonInstalls, optionally restricting by type. + * + * @param aTypes + * An array of types or null to get all types + * @param aCallback + * A callback to pass the array of AddonInstalls to + */ + getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) { + var installs = this.installs.filter(function(aInstall) { + // Appear to have actually removed cancelled installs from the provider + if (aInstall.state == AddonManager.STATE_CANCELLED) + return false; + + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1) + return false; + + return true; + }); + this._delayCallback(aCallback, installs); + }, + + /** + * Called when a new add-on has been enabled when only one add-on of that type + * can be enabled. + * + * @param aId + * The ID of the newly enabled add-on + * @param aType + * The type of the newly enabled add-on + * @param aPendingRestart + * true if the newly enabled add-on will only become enabled after a + * restart + */ + addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { + // Not implemented + }, + + /** + * Update the appDisabled property for all add-ons. + */ + updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() { + // Not needed + }, + + /** + * Called to get an AddonInstall to download and install an add-on from a URL. + * + * @param aUrl + * The URL to be installed + * @param aHash + * A hash for the install + * @param aName + * A name for the install + * @param aIconURL + * An icon URL for the install + * @param aVersion + * A version for the install + * @param aLoadGroup + * An nsILoadGroup to associate requests with + * @param aCallback + * A callback to pass the AddonInstall to + */ + getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL, + aVersion, aLoadGroup, aCallback) { + // Not yet implemented + }, + + /** + * Called to get an AddonInstall to install an add-on from a local file. + * + * @param aFile + * The file to be installed + * @param aCallback + * A callback to pass the AddonInstall to + */ + getInstallForFile: function MP_getInstallForFile(aFile, aCallback) { + // Not yet implemented + }, + + /** + * Called to test whether installing add-ons is enabled. + * + * @return true if installing is enabled + */ + isInstallEnabled: function MP_isInstallEnabled() { + return false; + }, + + /** + * Called to test whether this provider supports installing a particular + * mimetype. + * + * @param aMimetype + * The mimetype to check for + * @return true if the mimetype is supported + */ + supportsMimetype: function MP_supportsMimetype(aMimetype) { + return false; + }, + + /** + * Called to test whether installing add-ons from a URI is allowed. + * + * @param aUri + * The URI being installed from + * @return true if installing is allowed + */ + isInstallAllowed: function MP_isInstallAllowed(aUri) { + return false; + }, + + + /** *** Internal functions *****/ + + /** + * Delay calling a callback to fake a time-consuming async operation. + * The delay is specified by the apiDelay property, in milliseconds. + * Parameters to send to the callback should be specified as arguments after + * the aCallback argument. + * + * @param aCallback Callback to eventually call + */ + _delayCallback: function MP_delayCallback(aCallback, ...aArgs) { + if (!this.useAsyncCallbacks) { + aCallback(...aArgs); + return; + } + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + // Need to keep a reference to the timer, so it doesn't get GC'ed + this.callbackTimers.push(timer); + // Capture a stack trace where the timer was set + // needs the 'new Error' hack until bug 1007656 + this.timerLocations.set(timer, Log.stackTrace(new Error("dummy"))); + timer.initWithCallback(() => { + let idx = this.callbackTimers.indexOf(timer); + if (idx == -1) { + dump("MockProvider._delayCallback lost track of timer set at " + + (this.timerLocations.get(timer) || "unknown location") + "\n"); + } else { + this.callbackTimers.splice(idx, 1); + } + this.timerLocations.delete(timer); + aCallback(...aArgs); + }, this.apiDelay, timer.TYPE_ONE_SHOT); + } +}; + +/** *** Mock Addon object for the Mock Provider *****/ + +function MockAddon(aId, aName, aType, aOperationsRequiringRestart) { + // Only set required attributes. + this.id = aId || ""; + this.name = aName || ""; + this.type = aType || "extension"; + this.version = ""; + this.isCompatible = true; + this.providesUpdatesSecurely = true; + this.blocklistState = 0; + this._appDisabled = false; + this._userDisabled = false; + this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE; + this.scope = AddonManager.SCOPE_PROFILE; + this.isActive = true; + this.creator = ""; + this.pendingOperations = 0; + this._permissions = AddonManager.PERM_CAN_UNINSTALL | + AddonManager.PERM_CAN_ENABLE | + AddonManager.PERM_CAN_DISABLE | + AddonManager.PERM_CAN_UPGRADE; + this.operationsRequiringRestart = (aOperationsRequiringRestart != undefined) ? + aOperationsRequiringRestart : + (AddonManager.OP_NEEDS_RESTART_INSTALL | + AddonManager.OP_NEEDS_RESTART_UNINSTALL | + AddonManager.OP_NEEDS_RESTART_ENABLE | + AddonManager.OP_NEEDS_RESTART_DISABLE); +} + +MockAddon.prototype = { + get isCorrectlySigned() { + if (this.signedState === AddonManager.SIGNEDSTATE_NOT_REQUIRED) + return true; + return this.signedState > AddonManager.SIGNEDSTATE_MISSING; + }, + + get shouldBeActive() { + return !this.appDisabled && !this._userDisabled && + !(this.pendingOperations & AddonManager.PENDING_UNINSTALL); + }, + + get appDisabled() { + return this._appDisabled; + }, + + set appDisabled(val) { + if (val == this._appDisabled) + return val; + + AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]); + + var currentActive = this.shouldBeActive; + this._appDisabled = val; + var newActive = this.shouldBeActive; + this._updateActiveState(currentActive, newActive); + + return val; + }, + + get userDisabled() { + return this._userDisabled; + }, + + set userDisabled(val) { + if (val == this._userDisabled) + return val; + + var currentActive = this.shouldBeActive; + this._userDisabled = val; + var newActive = this.shouldBeActive; + this._updateActiveState(currentActive, newActive); + + return val; + }, + + get permissions() { + let permissions = this._permissions; + if (this.appDisabled || !this._userDisabled) + permissions &= ~AddonManager.PERM_CAN_ENABLE; + if (this.appDisabled || this._userDisabled) + permissions &= ~AddonManager.PERM_CAN_DISABLE; + return permissions; + }, + + set permissions(val) { + return this._permissions = val; + }, + + get applyBackgroundUpdates() { + return this._applyBackgroundUpdates; + }, + + set applyBackgroundUpdates(val) { + if (val != AddonManager.AUTOUPDATE_DEFAULT && + val != AddonManager.AUTOUPDATE_DISABLE && + val != AddonManager.AUTOUPDATE_ENABLE) { + ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val); + } + this._applyBackgroundUpdates = val; + AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]); + }, + + isCompatibleWith: function(aAppVersion, aPlatformVersion) { + return true; + }, + + findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { + // Tests can implement this if they need to + }, + + uninstall: function(aAlwaysAllowUndo = false) { + if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL) + && this.pendingOperations & AddonManager.PENDING_UNINSTALL) + throw Components.Exception("Add-on is already pending uninstall"); + + var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL); + this.pendingOperations |= AddonManager.PENDING_UNINSTALL; + AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart); + if (!needsRestart) { + this.pendingOperations -= AddonManager.PENDING_UNINSTALL; + this._provider.removeAddon(this); + } else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) { + this.isActive = false; + } + }, + + cancelUninstall: function() { + if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL)) + throw Components.Exception("Add-on is not pending uninstall"); + + this.pendingOperations -= AddonManager.PENDING_UNINSTALL; + this.isActive = this.shouldBeActive; + AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); + }, + + markAsSeen: function() { + this.seen = true; + }, + + _updateActiveState: function(currentActive, newActive) { + if (currentActive == newActive) + return; + + if (newActive == this.isActive) { + this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE); + AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); + } + else if (newActive) { + let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE); + this.pendingOperations |= AddonManager.PENDING_ENABLE; + AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart); + if (!needsRestart) { + this.isActive = newActive; + this.pendingOperations -= AddonManager.PENDING_ENABLE; + AddonManagerPrivate.callAddonListeners("onEnabled", this); + } + } + else { + let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE); + this.pendingOperations |= AddonManager.PENDING_DISABLE; + AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart); + if (!needsRestart) { + this.isActive = newActive; + this.pendingOperations -= AddonManager.PENDING_DISABLE; + AddonManagerPrivate.callAddonListeners("onDisabled", this); + } + } + } +}; + +/** *** Mock AddonInstall object for the Mock Provider *****/ + +function MockInstall(aName, aType, aAddonToInstall) { + this.name = aName || ""; + // Don't expose type until download completed + this._type = aType || "extension"; + this.type = null; + this.version = "1.0"; + this.iconURL = ""; + this.infoURL = ""; + this.state = AddonManager.STATE_AVAILABLE; + this.error = 0; + this.sourceURI = null; + this.file = null; + this.progress = 0; + this.maxProgress = -1; + this.certificate = null; + this.certName = ""; + this.existingAddon = null; + this.addon = null; + this._addonToInstall = aAddonToInstall; + this.listeners = []; + + // Another type of install listener for tests that want to check the results + // of code run from standard install listeners + this.testListeners = []; +} + +MockInstall.prototype = { + install: function() { + switch (this.state) { + case AddonManager.STATE_AVAILABLE: + this.state = AddonManager.STATE_DOWNLOADING; + if (!this.callListeners("onDownloadStarted")) { + this.state = AddonManager.STATE_CANCELLED; + this.callListeners("onDownloadCancelled"); + return; + } + + this.type = this._type; + + // Adding addon to MockProvider to be implemented when needed + if (this._addonToInstall) + this.addon = this._addonToInstall; + else { + this.addon = new MockAddon("", this.name, this.type); + this.addon.version = this.version; + this.addon.pendingOperations = AddonManager.PENDING_INSTALL; + } + this.addon.install = this; + if (this.existingAddon) { + if (!this.addon.id) + this.addon.id = this.existingAddon.id; + this.existingAddon.pendingUpgrade = this.addon; + this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE; + } + + this.state = AddonManager.STATE_DOWNLOADED; + this.callListeners("onDownloadEnded"); + + case AddonManager.STATE_DOWNLOADED: + this.state = AddonManager.STATE_INSTALLING; + if (!this.callListeners("onInstallStarted")) { + this.state = AddonManager.STATE_CANCELLED; + this.callListeners("onInstallCancelled"); + return; + } + + let needsRestart = (this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_INSTALL); + AddonManagerPrivate.callAddonListeners("onInstalling", this.addon, needsRestart); + if (!needsRestart) { + AddonManagerPrivate.callAddonListeners("onInstalled", this.addon); + } + + this.state = AddonManager.STATE_INSTALLED; + this.callListeners("onInstallEnded"); + break; + case AddonManager.STATE_DOWNLOADING: + case AddonManager.STATE_CHECKING: + case AddonManager.STATE_INSTALLING: + // Installation is already running + return; + default: + ok(false, "Cannot start installing when state = " + this.state); + } + }, + + cancel: function() { + switch (this.state) { + case AddonManager.STATE_AVAILABLE: + this.state = AddonManager.STATE_CANCELLED; + break; + case AddonManager.STATE_INSTALLED: + this.state = AddonManager.STATE_CANCELLED; + this._provider.removeInstall(this); + this.callListeners("onInstallCancelled"); + break; + default: + // Handling cancelling when downloading to be implemented when needed + ok(false, "Cannot cancel when state = " + this.state); + } + }, + + + addListener: function(aListener) { + if (!this.listeners.some(i => i == aListener)) + this.listeners.push(aListener); + }, + + removeListener: function(aListener) { + this.listeners = this.listeners.filter(i => i != aListener); + }, + + addTestListener: function(aListener) { + if (!this.testListeners.some(i => i == aListener)) + this.testListeners.push(aListener); + }, + + removeTestListener: function(aListener) { + this.testListeners = this.testListeners.filter(i => i != aListener); + }, + + callListeners: function(aMethod) { + var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners, + this, this.addon); + + // Call test listeners after standard listeners to remove race condition + // between standard and test listeners + for (let listener of this.testListeners) { + try { + if (aMethod in listener) + if (listener[aMethod].call(listener, this, this.addon) === false) + result = false; + } + catch (e) { + ok(false, "Test listener threw exception: " + e); + } + } + + return result; + } +}; + +function waitForCondition(condition, nextTest, errorMsg) { + let tries = 0; + let interval = setInterval(function() { + if (tries >= 30) { + ok(false, errorMsg); + moveOn(); + } + var conditionPassed; + try { + conditionPassed = condition(); + } catch (e) { + ok(false, e + "\n" + e.stack); + conditionPassed = false; + } + if (conditionPassed) { + moveOn(); + } + tries++; + }, 100); + let moveOn = function() { clearInterval(interval); nextTest(); }; +} + +function getTestPluginTag() { + let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let tags = ph.getPluginTags(); + + // Find the test plugin + for (let i = 0; i < tags.length; i++) { + if (tags[i].name == "Test Plug-in") + return tags[i]; + } + ok(false, "Unable to find plugin"); + return null; +} diff --git a/toolkit/mozapps/webextensions/test/browser/more_options.xul b/toolkit/mozapps/webextensions/test/browser/more_options.xul new file mode 100644 index 000000000..28dbb0a2e --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/more_options.xul @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/webextensions/test/browser/moz.build b/toolkit/mozapps/webextensions/test/browser/moz.build new file mode 100644 index 000000000..af04aaeef --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +BROWSER_CHROME_MANIFESTS += [ + 'browser-window.ini', + 'browser.ini', +] diff --git a/toolkit/mozapps/webextensions/test/browser/options.xul b/toolkit/mozapps/webextensions/test/browser/options.xul new file mode 100644 index 000000000..1b6827915 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/options.xul @@ -0,0 +1,12 @@ + + + + + Description Text Node + + This is a test, +

+

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/cookieRedirect.sjs b/toolkit/mozapps/webextensions/test/xpinstall/cookieRedirect.sjs new file mode 100644 index 000000000..92bccd9ec --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/cookieRedirect.sjs @@ -0,0 +1,24 @@ +// Simple script redirects to the query part of the uri if the cookie "xpinstall" +// has the value "true", otherwise gives a 500 error. + +function handleRequest(request, response) +{ + let cookie = null; + if (request.hasHeader("Cookie")) { + let cookies = request.getHeader("Cookie").split(";"); + for (let i = 0; i < cookies.length; i++) { + if (cookies[i].substring(0, 10) == "xpinstall=") + cookie = cookies[i].substring(10); + } + } + + if (cookie == "true") { + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", request.queryString); + response.write("See " + request.queryString); + } + else { + response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); + response.write("Invalid request"); + } +} diff --git a/toolkit/mozapps/webextensions/test/xpinstall/corrupt.xpi b/toolkit/mozapps/webextensions/test/xpinstall/corrupt.xpi new file mode 100644 index 000000000..35d7bd5e5 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/corrupt.xpi @@ -0,0 +1 @@ +This is a corrupt zip file diff --git a/toolkit/mozapps/webextensions/test/xpinstall/empty.xpi b/toolkit/mozapps/webextensions/test/xpinstall/empty.xpi new file mode 100644 index 000000000..74ed2b817 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/empty.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/enabled.html b/toolkit/mozapps/webextensions/test/xpinstall/enabled.html new file mode 100644 index 000000000..370cde8fb --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/enabled.html @@ -0,0 +1,24 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/hashRedirect.sjs b/toolkit/mozapps/webextensions/test/xpinstall/hashRedirect.sjs new file mode 100644 index 000000000..324a092a3 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/hashRedirect.sjs @@ -0,0 +1,15 @@ +// Simple script redirects takes the query part of te request and splits it on +// the | character. Anything before is included as the X-Target-Digest header +// the latter part is used as the url to redirect to + +function handleRequest(request, response) +{ + let pos = request.queryString.indexOf("|"); + let header = request.queryString.substring(0, pos); + let url = request.queryString.substring(pos + 1); + + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("X-Target-Digest", header); + response.setHeader("Location", url); + response.write("See " + url); +} diff --git a/toolkit/mozapps/webextensions/test/xpinstall/head.js b/toolkit/mozapps/webextensions/test/xpinstall/head.js new file mode 100644 index 000000000..197fe3fac --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/head.js @@ -0,0 +1,434 @@ +const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/"; + +const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; +const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR; +const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; +const PROMPT_URL = "chrome://global/content/commonDialog.xul"; +const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul"; +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts"; +const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin"; +const PREF_CUSTOM_CONFIRMATION_UI = "xpinstall.customConfirmationUI"; +const CHROME_NAME = "mochikit"; + +function getChromeRoot(path) { + if (path === undefined) { + return "chrome://" + CHROME_NAME + "/content/browser/" + RELATIVE_DIR + } + return getRootDirectory(path); +} + +function extractChromeRoot(path) { + var chromeRootPath = getChromeRoot(path); + var jar = getJar(chromeRootPath); + if (jar) { + var tmpdir = extractJarToTmp(jar); + return "file://" + tmpdir.path + "/"; + } + return chromeRootPath; +} + +Services.prefs.setBoolPref(PREF_CUSTOM_CONFIRMATION_UI, false); +registerCleanupFunction(() => { + Services.prefs.clearUserPref(PREF_CUSTOM_CONFIRMATION_UI); +}); + +/** + * This is a test harness designed to handle responding to UI during the process + * of installing an XPI. A test can set callbacks to hear about specific parts + * of the sequence. + * Before use setup must be called and finish must be called afterwards. + */ +var Harness = { + // If set then the callback is called when an install is attempted and + // software installation is disabled. + installDisabledCallback: null, + // If set then the callback is called when an install is attempted and + // then canceled. + installCancelledCallback: null, + // If set then the callback will be called when an install's origin is blocked. + installOriginBlockedCallback: null, + // If set then the callback will be called when an install is blocked by the + // whitelist. The callback should return true to continue with the install + // anyway. + installBlockedCallback: null, + // If set will be called in the event of authentication being needed to get + // the xpi. Should return a 2 element array of username and password, or + // null to not authenticate. + authenticationCallback: null, + // If set this will be called to allow checking the contents of the xpinstall + // confirmation dialog. The callback should return true to continue the install. + installConfirmCallback: null, + // If set will be called when downloading of an item has begun. + downloadStartedCallback: null, + // If set will be called during the download of an item. + downloadProgressCallback: null, + // If set will be called when an xpi fails to download. + downloadFailedCallback: null, + // If set will be called when an xpi download is cancelled. + downloadCancelledCallback: null, + // If set will be called when downloading of an item has ended. + downloadEndedCallback: null, + // If set will be called when installation by the extension manager of an xpi + // item starts + installStartedCallback: null, + // If set will be called when an xpi fails to install. + installFailedCallback: null, + // If set will be called when each xpi item to be installed completes + // installation. + installEndedCallback: null, + // If set will be called when all triggered items are installed or the install + // is canceled. + installsCompletedCallback: null, + // If set the harness will wait for this DOM event before calling + // installsCompletedCallback + finalContentEvent: null, + + waitingForEvent: false, + pendingCount: null, + installCount: null, + runningInstalls: null, + + waitingForFinish: false, + + // A unique value to return from the installConfirmCallback to indicate that + // the install UI shouldn't be closed automatically + leaveOpen: {}, + + // Setup and tear down functions + setup: function() { + if (!this.waitingForFinish) { + waitForExplicitFinish(); + this.waitingForFinish = true; + + Services.prefs.setBoolPref(PREF_INSTALL_REQUIRESECUREORIGIN, false); + + Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); + Services.obs.addObserver(this, "addon-install-started", false); + Services.obs.addObserver(this, "addon-install-disabled", false); + Services.obs.addObserver(this, "addon-install-origin-blocked", false); + Services.obs.addObserver(this, "addon-install-blocked", false); + Services.obs.addObserver(this, "addon-install-failed", false); + Services.obs.addObserver(this, "addon-install-complete", false); + + AddonManager.addInstallListener(this); + + Services.wm.addListener(this); + + var self = this; + registerCleanupFunction(function() { + Services.prefs.clearUserPref(PREF_LOGGING_ENABLED); + Services.prefs.clearUserPref(PREF_INSTALL_REQUIRESECUREORIGIN); + Services.obs.removeObserver(self, "addon-install-started"); + Services.obs.removeObserver(self, "addon-install-disabled"); + Services.obs.removeObserver(self, "addon-install-origin-blocked"); + Services.obs.removeObserver(self, "addon-install-blocked"); + Services.obs.removeObserver(self, "addon-install-failed"); + Services.obs.removeObserver(self, "addon-install-complete"); + + AddonManager.removeInstallListener(self); + + Services.wm.removeListener(self); + + AddonManager.getAllInstalls(function(aInstalls) { + is(aInstalls.length, 0, "Should be no active installs at the end of the test"); + aInstalls.forEach(function(aInstall) { + info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); + aInstall.cancel(); + }); + }); + }); + } + + this.installCount = 0; + this.pendingCount = 0; + this.runningInstalls = []; + }, + + finish: function() { + finish(); + }, + + endTest: function() { + let callback = this.installsCompletedCallback; + let count = this.installCount; + + is(this.runningInstalls.length, 0, "Should be no running installs left"); + this.runningInstalls.forEach(function(aInstall) { + info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); + }); + + this.installOriginBlockedCallback = null; + this.installBlockedCallback = null; + this.authenticationCallback = null; + this.installConfirmCallback = null; + this.downloadStartedCallback = null; + this.downloadProgressCallback = null; + this.downloadCancelledCallback = null; + this.downloadFailedCallback = null; + this.downloadEndedCallback = null; + this.installStartedCallback = null; + this.installFailedCallback = null; + this.installEndedCallback = null; + this.installsCompletedCallback = null; + this.runningInstalls = null; + + if (callback) + executeSoon(() => callback(count)); + }, + + // Window open handling + windowReady: function(window) { + if (window.document.location.href == XPINSTALL_URL) { + if (this.installBlockedCallback) + ok(false, "Should have been blocked by the whitelist"); + this.pendingCount = window.document.getElementById("itemList").childNodes.length; + + // If there is a confirm callback then its return status determines whether + // to install the items or not. If not the test is over. + let result = true; + if (this.installConfirmCallback) { + result = this.installConfirmCallback(window); + if (result === this.leaveOpen) + return; + } + + if (!result) { + window.document.documentElement.cancelDialog(); + } + else { + // Initially the accept button is disabled on a countdown timer + var button = window.document.documentElement.getButton("accept"); + button.disabled = false; + window.document.documentElement.acceptDialog(); + } + } + else if (window.document.location.href == PROMPT_URL) { + var promptType = window.args.promptType; + switch (promptType) { + case "alert": + case "alertCheck": + case "confirmCheck": + case "confirm": + case "confirmEx": + window.document.documentElement.acceptDialog(); + break; + case "promptUserAndPass": + // This is a login dialog, hopefully an authentication prompt + // for the xpi. + if (this.authenticationCallback) { + var auth = this.authenticationCallback(); + if (auth && auth.length == 2) { + window.document.getElementById("loginTextbox").value = auth[0]; + window.document.getElementById("password1Textbox").value = auth[1]; + window.document.documentElement.acceptDialog(); + } + else { + window.document.documentElement.cancelDialog(); + } + } + else { + window.document.documentElement.cancelDialog(); + } + break; + default: + ok(false, "prompt type " + promptType + " not handled in test."); + break; + } + } + }, + + // Install blocked handling + + installDisabled: function(installInfo) { + ok(!!this.installDisabledCallback, "Installation shouldn't have been disabled"); + if (this.installDisabledCallback) + this.installDisabledCallback(installInfo); + this.expectingCancelled = true; + this.expectingCancelled = false; + this.endTest(); + }, + + installCancelled: function(installInfo) { + if (this.expectingCancelled) + return; + + ok(!!this.installCancelledCallback, "Installation shouldn't have been cancelled"); + if (this.installCancelledCallback) + this.installCancelledCallback(installInfo); + this.endTest(); + }, + + installOriginBlocked: function(installInfo) { + ok(!!this.installOriginBlockedCallback, "Shouldn't have been blocked"); + if (this.installOriginBlockedCallback) + this.installOriginBlockedCallback(installInfo); + this.endTest(); + }, + + installBlocked: function(installInfo) { + ok(!!this.installBlockedCallback, "Shouldn't have been blocked by the whitelist"); + if (this.installBlockedCallback && this.installBlockedCallback(installInfo)) { + this.installBlockedCallback = null; + installInfo.install(); + } + else { + this.expectingCancelled = true; + installInfo.installs.forEach(function(install) { + install.cancel(); + }); + this.expectingCancelled = false; + this.endTest(); + } + }, + + // nsIWindowMediatorListener + + onWindowTitleChange: function(window, title) { + }, + + onOpenWindow: function(window) { + var domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindow); + var self = this; + waitForFocus(function() { + self.windowReady(domwindow); + }, domwindow); + }, + + onCloseWindow: function(window) { + }, + + // Addon Install Listener + + onNewInstall: function(install) { + this.runningInstalls.push(install); + + if (this.finalContentEvent && !this.waitingForEvent) { + this.waitingForEvent = true; + info("Waiting for " + this.finalContentEvent); + let mm = gBrowser.selectedBrowser.messageManager; + mm.loadFrameScript(`data:,content.addEventListener("${this.finalContentEvent}", () => { sendAsyncMessage("Test:GotNewInstallEvent"); });`, false); + let win = gBrowser.contentWindow; + let listener = () => { + info("Saw " + this.finalContentEvent); + mm.removeMessageListener("Test:GotNewInstallEvent", listener); + this.waitingForEvent = false; + if (this.pendingCount == 0) + this.endTest(); + } + mm.addMessageListener("Test:GotNewInstallEvent", listener); + } + }, + + onDownloadStarted: function(install) { + this.pendingCount++; + if (this.downloadStartedCallback) + this.downloadStartedCallback(install); + }, + + onDownloadProgress: function(install) { + if (this.downloadProgressCallback) + this.downloadProgressCallback(install); + }, + + onDownloadEnded: function(install) { + if (this.downloadEndedCallback) + this.downloadEndedCallback(install); + }, + + onDownloadCancelled: function(install) { + isnot(this.runningInstalls.indexOf(install), -1, + "Should only see cancelations for started installs"); + this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1); + + if (this.downloadCancelledCallback) + this.downloadCancelledCallback(install); + this.checkTestEnded(); + }, + + onDownloadFailed: function(install) { + if (this.downloadFailedCallback) + this.downloadFailedCallback(install); + this.checkTestEnded(); + }, + + onInstallStarted: function(install) { + if (this.installStartedCallback) + this.installStartedCallback(install); + }, + + onInstallEnded: function(install, addon) { + if (this.installEndedCallback) + this.installEndedCallback(install, addon); + this.installCount++; + this.checkTestEnded(); + }, + + onInstallFailed: function(install) { + if (this.installFailedCallback) + this.installFailedCallback(install); + this.checkTestEnded(); + }, + + checkTestEnded: function() { + if (--this.pendingCount == 0 && !this.waitingForEvent) + this.endTest(); + }, + + // nsIObserver + + observe: function(subject, topic, data) { + var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo); + switch (topic) { + case "addon-install-started": + is(this.runningInstalls.length, installInfo.installs.length, + "Should have seen the expected number of installs started"); + break; + case "addon-install-disabled": + this.installDisabled(installInfo); + break; + case "addon-install-cancelled": + this.installCancelled(installInfo); + break; + case "addon-install-origin-blocked": + this.installOriginBlocked(installInfo); + break; + case "addon-install-blocked": + this.installBlocked(installInfo); + break; + case "addon-install-failed": + installInfo.installs.forEach(function(aInstall) { + isnot(this.runningInstalls.indexOf(aInstall), -1, + "Should only see failures for started installs"); + + ok(aInstall.error != 0 || aInstall.addon.appDisabled, + "Failed installs should have an error or be appDisabled"); + + this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); + }, this); + break; + case "addon-install-complete": + installInfo.installs.forEach(function(aInstall) { + isnot(this.runningInstalls.indexOf(aInstall), -1, + "Should only see completed events for started installs"); + + is(aInstall.error, 0, "Completed installs should have no error"); + ok(!aInstall.appDisabled, "Completed installs should not be appDisabled"); + + // Complete installs are either in the INSTALLED or CANCELLED state + // since the test may cancel installs the moment they complete. + ok(aInstall.state == AddonManager.STATE_INSTALLED || + aInstall.state == AddonManager.STATE_CANCELLED, + "Completed installs should be in the right state"); + + this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); + }, this); + break; + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsIWindowMediatorListener, + Ci.nsISupports]) +} diff --git a/toolkit/mozapps/webextensions/test/xpinstall/incompatible.xpi b/toolkit/mozapps/webextensions/test/xpinstall/incompatible.xpi new file mode 100644 index 000000000..262ed38a7 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/incompatible.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/installchrome.html b/toolkit/mozapps/webextensions/test/xpinstall/installchrome.html new file mode 100644 index 000000000..6abee2ef3 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/installchrome.html @@ -0,0 +1,22 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/installtrigger.html b/toolkit/mozapps/webextensions/test/xpinstall/installtrigger.html new file mode 100644 index 000000000..65cab1ef1 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/installtrigger.html @@ -0,0 +1,44 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/installtrigger_frame.html b/toolkit/mozapps/webextensions/test/xpinstall/installtrigger_frame.html new file mode 100644 index 000000000..2b302642e --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/installtrigger_frame.html @@ -0,0 +1,29 @@ + + + + + + + +InstallTrigger frame tests + + + + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/multipackage.xpi b/toolkit/mozapps/webextensions/test/xpinstall/multipackage.xpi new file mode 100644 index 000000000..d52f28c28 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/multipackage.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/navigate.html b/toolkit/mozapps/webextensions/test/xpinstall/navigate.html new file mode 100644 index 000000000..5a6903eb9 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/navigate.html @@ -0,0 +1,26 @@ + + + + + + + +Navigation tests + + + + +

Test Link

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/redirect.sjs b/toolkit/mozapps/webextensions/test/xpinstall/redirect.sjs new file mode 100644 index 000000000..d248bfbc7 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/redirect.sjs @@ -0,0 +1,45 @@ +// Script has two modes based on the query string. If the mode is "setup" then +// parameters from the query string configure the redirection. If the mode is +// "redirect" then a redirect is returned + +function handleRequest(request, response) +{ + let parts = request.queryString.split("&"); + let settings = {}; + + parts.forEach(function(aString) { + let [k, v] = aString.split("="); + settings[k] = decodeURIComponent(v); + }) + + if (settings.mode == "setup") { + delete settings.mode; + + // Object states must be an nsISupports + var state = { + settings: settings, + QueryInterface: function(aIid) { + if (aIid.equals(Components.interfaces.nsISupports)) + return settings; + throw Components.results.NS_ERROR_NO_INTERFACE; + } + } + state.wrappedJSObject = state; + + setObjectState("xpinstall-redirect-settings", state); + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/plain"); + response.write("Setup complete"); + } + else if (settings.mode == "redirect") { + getObjectState("xpinstall-redirect-settings", function(aObject) { + settings = aObject.wrappedJSObject.settings; + }); + + response.setStatusLine(request.httpVersion, 302, "Found"); + for (var name in settings) { + response.setHeader(name, settings[name]); + } + response.write("Done"); + } +} diff --git a/toolkit/mozapps/webextensions/test/xpinstall/restartless-unsigned.xpi b/toolkit/mozapps/webextensions/test/xpinstall/restartless-unsigned.xpi new file mode 100644 index 000000000..8e76bd052 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/restartless-unsigned.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/restartless.xpi b/toolkit/mozapps/webextensions/test/xpinstall/restartless.xpi new file mode 100644 index 000000000..9fee8f60b Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/restartless.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed-multipackage.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed-multipackage.xpi new file mode 100644 index 000000000..11fbe1861 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed-multipackage.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed-no-cn.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed-no-cn.xpi new file mode 100644 index 000000000..90d3a3ce6 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed-no-cn.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed-no-o.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed-no-o.xpi new file mode 100644 index 000000000..19b754038 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed-no-o.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed-tampered.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed-tampered.xpi new file mode 100644 index 000000000..8c951881e Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed-tampered.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed-untrusted.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed-untrusted.xpi new file mode 100644 index 000000000..09789d189 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed-untrusted.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed.xpi new file mode 100644 index 000000000..bd7f78b7c Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/signed2.xpi b/toolkit/mozapps/webextensions/test/xpinstall/signed2.xpi new file mode 100644 index 000000000..085efbbf7 Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/signed2.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/slowinstall.sjs b/toolkit/mozapps/webextensions/test/xpinstall/slowinstall.sjs new file mode 100644 index 000000000..5f767a8f4 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/slowinstall.sjs @@ -0,0 +1,101 @@ +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/osfile.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +const RELATIVE_PATH = "browser/toolkit/mozapps/extensions/test/xpinstall" +const NOTIFICATION_TOPIC = "slowinstall-complete"; + +/** + * Helper function to create a JS object representing the url parameters from + * the request's queryString. + * + * @param aQueryString + * The request's query string. + * @return A JS object representing the url parameters from the request's + * queryString. + */ +function parseQueryString(aQueryString) { + var paramArray = aQueryString.split("&"); + var regex = /^([^=]+)=(.*)$/; + var params = {}; + for (var i = 0, sz = paramArray.length; i < sz; i++) { + var match = regex.exec(paramArray[i]); + if (!match) + throw "Bad parameter in queryString! '" + paramArray[i] + "'"; + params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); + } + + return params; +} + +function handleRequest(aRequest, aResponse) { + let id = +getState("ID"); + setState("ID", "" + (id + 1)); + + function LOG(str) { + dump("slowinstall.sjs[" + id + "]: " + str + "\n"); + } + + aResponse.setStatusLine(aRequest.httpVersion, 200, "OK"); + + var params = { }; + if (aRequest.queryString) + params = parseQueryString(aRequest.queryString); + + if (params.file) { + let xpiFile = ""; + + function complete_download() { + LOG("Completing download"); + downloadPaused = false; + + try { + // Doesn't seem to be a sane way to read using OS.File and write to an + // nsIOutputStream so here we are. + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(xpiFile); + let stream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + stream.init(file, -1, -1, stream.DEFER_OPEN + stream.CLOSE_ON_EOF); + + NetUtil.asyncCopy(stream, aResponse.bodyOutputStream, () => { + LOG("Download complete"); + aResponse.finish(); + }); + } + catch (e) { + LOG("Exception " + e); + } + } + + let waitForComplete = new Promise(resolve => { + function complete() { + Services.obs.removeObserver(complete, NOTIFICATION_TOPIC); + resolve(); + } + + Services.obs.addObserver(complete, NOTIFICATION_TOPIC, false); + }); + + aResponse.processAsync(); + + OS.File.getCurrentDirectory().then(dir => { + xpiFile = OS.Path.join(dir, ...RELATIVE_PATH.split("/"), params.file); + LOG("Starting slow download of " + xpiFile); + + OS.File.stat(xpiFile).then(info => { + aResponse.setHeader("Content-Type", "binary/octet-stream"); + aResponse.setHeader("Content-Length", info.size.toString()); + + LOG("Download paused"); + waitForComplete.then(complete_download); + }); + }); + } + else if (params.continue) { + dump("slowinstall.sjs: Received signal to complete all current downloads.\n"); + Services.obs.notifyObservers(null, NOTIFICATION_TOPIC, null); + } +} diff --git a/toolkit/mozapps/webextensions/test/xpinstall/startsoftwareupdate.html b/toolkit/mozapps/webextensions/test/xpinstall/startsoftwareupdate.html new file mode 100644 index 000000000..50083ca90 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/startsoftwareupdate.html @@ -0,0 +1,20 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/theme.xpi b/toolkit/mozapps/webextensions/test/xpinstall/theme.xpi new file mode 100644 index 000000000..74e650b4a Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/theme.xpi differ diff --git a/toolkit/mozapps/webextensions/test/xpinstall/triggerredirect.html b/toolkit/mozapps/webextensions/test/xpinstall/triggerredirect.html new file mode 100644 index 000000000..42e0e1cd0 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpinstall/triggerredirect.html @@ -0,0 +1,36 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/webextensions/test/xpinstall/unsigned.xpi b/toolkit/mozapps/webextensions/test/xpinstall/unsigned.xpi new file mode 100644 index 000000000..51b00475a Binary files /dev/null and b/toolkit/mozapps/webextensions/test/xpinstall/unsigned.xpi differ -- cgit v1.2.3