addons.js (3359B)
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 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { Actor } = require("resource://devtools/shared/protocol.js"); 8 const { 9 addonsSpec, 10 } = require("resource://devtools/shared/specs/addon/addons.js"); 11 12 const { AddonManager } = ChromeUtils.importESModule( 13 "resource://gre/modules/AddonManager.sys.mjs", 14 { global: "shared" } 15 ); 16 const { FileUtils } = ChromeUtils.importESModule( 17 "resource://gre/modules/FileUtils.sys.mjs", 18 { global: "contextual" } 19 ); 20 21 // This actor is used by DevTools as well as external tools such as webext-run 22 // and the Firefox VS-Code plugin. see bug #1578108 23 class AddonsActor extends Actor { 24 constructor(conn) { 25 super(conn, addonsSpec); 26 } 27 28 async installTemporaryAddon(addonPath, openDevTools) { 29 let addonFile; 30 let addon; 31 try { 32 addonFile = new FileUtils.File(addonPath); 33 addon = await AddonManager.installTemporaryAddon(addonFile); 34 } catch (error) { 35 let msg = `${error}`; 36 if (error.additionalErrors?.length) { 37 // The generic "Extension is invalid" error does not offer any concrete 38 // advice. Include the additional details to help with debugging. 39 msg += `\n${error.additionalErrors.join("\n")}`; 40 } 41 throw new Error(`Could not install add-on at '${addonPath}': ${msg}`); 42 } 43 44 Services.obs.notifyObservers(null, "devtools-installed-addon", addon.id); 45 46 // Try to open DevTools for the installed add-on. 47 // Note that it will only work on Firefox Desktop. 48 // On Android, we don't ship DevTools UI. 49 // about:debugging is only using this API when debugging its own firefox instance, 50 // so for now, there is no chance of calling this on Android. 51 if (openDevTools) { 52 // This module is typically loaded in the loader spawn by DevToolsStartup, 53 // in a distinct compartment thanks to useDistinctSystemPrincipalLoader 54 // and global flag. 55 // But here we want to reuse the shared module loader. 56 // We do not want to load devtools.js in the server's distinct module loader. 57 const loader = ChromeUtils.importESModule( 58 "resource://devtools/shared/loader/Loader.sys.mjs", 59 { global: "shared" } 60 ); 61 const { 62 gDevTools, 63 // eslint-disable-next-line mozilla/reject-some-requires 64 } = loader.require("resource://devtools/client/framework/devtools.js"); 65 gDevTools.showToolboxForWebExtension(addon.id); 66 } 67 68 // TODO: once the add-on actor has been refactored to use 69 // protocol.js, we could return it directly. 70 // return new AddonTargetActor(this.conn, addon); 71 72 // Return a pseudo add-on object that a calling client can work 73 // with. Provide a flag that the client can use to detect when it 74 // gets upgraded to a real actor object. 75 return { id: addon.id, actor: false }; 76 } 77 78 async uninstallAddon(addonId) { 79 const addon = await AddonManager.getAddonByID(addonId); 80 81 // We only support uninstallation of temporarily loaded add-ons at the 82 // moment. 83 if (!addon?.temporarilyInstalled) { 84 throw new Error(`Could not uninstall add-on "${addonId}"`); 85 } 86 87 await addon.uninstall(); 88 } 89 } 90 91 exports.AddonsActor = AddonsActor;