summaryrefslogtreecommitdiffstats
path: root/toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs')
-rw-r--r--toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs112
1 files changed, 112 insertions, 0 deletions
diff --git a/toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs b/toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs
new file mode 100644
index 0000000000..cf57662b2d
--- /dev/null
+++ b/toolkit/components/normandy/lib/NormandyAddonManager.sys.mjs
@@ -0,0 +1,112 @@
+/* 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/. */
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+});
+
+export const NormandyAddonManager = {
+ async downloadAndInstall({
+ createError,
+ extensionDetails,
+ applyNormandyChanges,
+ undoNormandyChanges,
+ onInstallStarted,
+ reportError,
+ }) {
+ const { extension_id, hash, hash_algorithm, version, xpi } =
+ extensionDetails;
+
+ const downloadDeferred = lazy.PromiseUtils.defer();
+ const installDeferred = lazy.PromiseUtils.defer();
+
+ const install = await lazy.AddonManager.getInstallForURL(xpi, {
+ hash: `${hash_algorithm}:${hash}`,
+ telemetryInfo: { source: "internal" },
+ });
+
+ const listener = {
+ onInstallStarted(cbInstall) {
+ const versionMatches = cbInstall.addon.version === version;
+ const idMatches = cbInstall.addon.id === extension_id;
+
+ if (!versionMatches || !idMatches) {
+ installDeferred.reject(createError("metadata-mismatch"));
+ return false; // cancel the installation, server metadata does not match downloaded add-on
+ }
+
+ if (onInstallStarted) {
+ return onInstallStarted(cbInstall, installDeferred);
+ }
+
+ return true;
+ },
+
+ onDownloadFailed() {
+ downloadDeferred.reject(
+ createError("download-failure", {
+ detail: lazy.AddonManager.errorToString(install.error),
+ })
+ );
+ },
+
+ onDownloadEnded() {
+ downloadDeferred.resolve();
+ return false; // temporarily pause installation for Normandy bookkeeping
+ },
+
+ onInstallFailed() {
+ installDeferred.reject(
+ createError("install-failure", {
+ detail: lazy.AddonManager.errorToString(install.error),
+ })
+ );
+ },
+
+ onInstallEnded() {
+ installDeferred.resolve();
+ },
+ };
+
+ install.addListener(listener);
+
+ // Download the add-on
+ try {
+ install.install();
+ await downloadDeferred.promise;
+ } catch (err) {
+ reportError(err);
+ install.removeListener(listener);
+ throw err;
+ }
+
+ // Complete any book-keeping
+ try {
+ await applyNormandyChanges(install);
+ } catch (err) {
+ reportError(err);
+ install.removeListener(listener);
+ install.cancel();
+ throw err;
+ }
+
+ // Finish paused installation
+ try {
+ install.install();
+ await installDeferred.promise;
+ } catch (err) {
+ reportError(err);
+ install.removeListener(listener);
+ await undoNormandyChanges();
+ throw err;
+ }
+
+ install.removeListener(listener);
+
+ return [install.addon.id, install.addon.version];
+ },
+};