File: addon.js

package info (click to toggle)
firefox-esr 68.10.0esr-1~deb9u1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 3,143,932 kB
  • sloc: cpp: 5,227,879; javascript: 4,315,531; ansic: 2,467,042; python: 794,975; java: 349,993; asm: 232,034; xml: 228,320; sh: 82,008; lisp: 41,202; makefile: 22,347; perl: 15,555; objc: 5,277; cs: 4,725; yacc: 1,778; ada: 1,681; pascal: 1,673; lex: 1,417; exp: 527; php: 436; ruby: 225; awk: 162; sed: 53; csh: 44
file content (136 lines) | stat: -rw-r--r-- 3,748 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* 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 { AddonManager } = ChromeUtils.import(
  "resource://gre/modules/AddonManager.jsm"
);
const { FileUtils } = ChromeUtils.import(
  "resource://gre/modules/FileUtils.jsm"
);

const { UnknownError } = ChromeUtils.import(
  "chrome://marionette/content/error.js"
);

this.EXPORTED_SYMBOLS = ["Addon"];

// from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
const ERRORS = {
  [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
  [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
  [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
  [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
  [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
};

async function installAddon(file) {
  let install = await AddonManager.getInstallForFile(file, null, {
    source: "internal",
  });

  if (install.error) {
    throw new UnknownError(ERRORS[install.error]);
  }

  return install.install().catch(err => {
    throw new UnknownError(ERRORS[install.error]);
  });
}

/** Installs addons by path and uninstalls by ID. */
class Addon {
  /**
   * Install a Firefox addon.
   *
   * If the addon is restartless, it can be used right away.  Otherwise a
   * restart is required.
   *
   * Temporary addons will automatically be uninstalled on shutdown and
   * do not need to be signed, though they must be restartless.
   *
   * @param {string} path
   *     Full path to the extension package archive.
   * @param {boolean=} temporary
   *     True to install the addon temporarily, false (default) otherwise.
   *
   * @return {Promise.<string>}
   *     Addon ID.
   *
   * @throws {UnknownError}
   *     If there is a problem installing the addon.
   */
  static async install(path, temporary = false) {
    let addon;
    let file;

    try {
      file = new FileUtils.File(path);
    } catch (e) {
      throw new UnknownError(`Expected absolute path: ${e}`, e);
    }

    if (!file.exists()) {
      throw new UnknownError(`No such file or directory: ${path}`);
    }

    try {
      if (temporary) {
        addon = await AddonManager.installTemporaryAddon(file);
      } else {
        addon = await installAddon(file);
      }
    } catch (e) {
      throw new UnknownError(
        `Could not install add-on: ${path}: ${e.message}`,
        e
      );
    }

    return addon.id;
  }

  /**
   * Uninstall a Firefox addon.
   *
   * If the addon is restartless it will be uninstalled right away.
   * Otherwise, Firefox must be restarted for the change to take effect.
   *
   * @param {string} id
   *     ID of the addon to uninstall.
   *
   * @return {Promise}
   *
   * @throws {UnknownError}
   *     If there is a problem uninstalling the addon.
   */
  static async uninstall(id) {
    let candidate = await AddonManager.getAddonByID(id);

    return new Promise(resolve => {
      let listener = {
        onOperationCancelled: addon => {
          if (addon.id === candidate.id) {
            AddonManager.removeAddonListener(listener);
            throw new UnknownError(
              `Uninstall of ${candidate.id} has been canceled`
            );
          }
        },

        onUninstalled: addon => {
          if (addon.id === candidate.id) {
            AddonManager.removeAddonListener(listener);
            resolve();
          }
        },
      };

      AddonManager.addAddonListener(listener);
      candidate.uninstall();
    });
  }
}
this.Addon = Addon;