1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const EXPORTED_SYMBOLS = ["Addon"];
9 const { XPCOMUtils } = ChromeUtils.import(
10 "resource://gre/modules/XPCOMUtils.jsm"
15 XPCOMUtils.defineLazyModuleGetters(lazy, {
16 AddonManager: "resource://gre/modules/AddonManager.jsm",
17 FileUtils: "resource://gre/modules/FileUtils.jsm",
19 error: "chrome://remote/content/shared/webdriver/Errors.jsm",
22 // from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
24 [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
25 [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
26 [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
27 [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
28 [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
31 async function installAddon(file) {
32 let install = await lazy.AddonManager.getInstallForFile(file, null, {
37 throw new lazy.error.UnknownError(ERRORS[install.error]);
40 return install.install().catch(err => {
41 throw new lazy.error.UnknownError(ERRORS[install.error]);
45 /** Installs addons by path and uninstalls by ID. */
48 * Install a Firefox addon.
50 * If the addon is restartless, it can be used right away. Otherwise a
51 * restart is required.
53 * Temporary addons will automatically be uninstalled on shutdown and
54 * do not need to be signed, though they must be restartless.
56 * @param {string} path
57 * Full path to the extension package archive.
58 * @param {boolean=} temporary
59 * True to install the addon temporarily, false (default) otherwise.
61 * @return {Promise.<string>}
64 * @throws {UnknownError}
65 * If there is a problem installing the addon.
67 static async install(path, temporary = false) {
72 file = new lazy.FileUtils.File(path);
74 throw new lazy.error.UnknownError(`Expected absolute path: ${e}`, e);
78 throw new lazy.error.UnknownError(`No such file or directory: ${path}`);
83 addon = await lazy.AddonManager.installTemporaryAddon(file);
85 addon = await installAddon(file);
88 throw new lazy.error.UnknownError(
89 `Could not install add-on: ${path}: ${e.message}`,
98 * Uninstall a Firefox addon.
100 * If the addon is restartless it will be uninstalled right away.
101 * Otherwise, Firefox must be restarted for the change to take effect.
104 * ID of the addon to uninstall.
108 * @throws {UnknownError}
109 * If there is a problem uninstalling the addon.
111 static async uninstall(id) {
112 let candidate = await lazy.AddonManager.getAddonByID(id);
113 if (candidate === null) {
114 // `AddonManager.getAddonByID` never rejects but instead
115 // returns `null` if the requested addon cannot be found.
116 throw new lazy.error.UnknownError(`Addon ${id} is not installed`);
119 return new Promise(resolve => {
121 onOperationCancelled: addon => {
122 if (addon.id === candidate.id) {
123 lazy.AddonManager.removeAddonListener(listener);
124 throw new lazy.error.UnknownError(
125 `Uninstall of ${candidate.id} has been canceled`
130 onUninstalled: addon => {
131 if (addon.id === candidate.id) {
132 lazy.AddonManager.removeAddonListener(listener);
138 lazy.AddonManager.addAddonListener(listener);
139 candidate.uninstall();