tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

managing-extensions.rst (9283B)


      1 GeckoView Extension Managing API
      2 ================================
      3 
      4 Agi Sferro <agi@sferro.dev>
      5 
      6 November 19th, 2019
      7 
      8 Introduction
      9 ------------
     10 
     11 This document describes the API for installing, uninstalling and updating
     12 Extensions with GeckoView.
     13 
     14 Installing an extension provides the extension the ability to run at startup
     15 time, especially useful for e.g. extensions that intercept network requests,
     16 like an ad-blocker or a proxy extension. It also provides additional security
     17 from third-party extensions like signature checking and prompting the user for
     18 permissions.
     19 
     20 For this version of the API we will assume that the extension store is backed
     21 by ``addons.mozilla.org``, and so are the signatures. Running a third-party
     22 extension store is something we might consider in the future but explicitly not
     23 in scope for this document.
     24 
     25 API
     26 ---
     27 
     28 The embedder will be able to install, uninstall, enable, disable and update
     29 extensions using the similarly-named APIs.
     30 
     31 Installing
     32 ^^^^^^^^^^
     33 
     34 Gecko will download the extension pointed by the URI provided in install, parse
     35 the manifest and signature and provide an ``onInstallPrompt`` callback with the
     36 list of permissions requested by the extension and some information about the
     37 extension.
     38 
     39 The embedder will be able to install bundled first-party extensions using
     40 ``installBuiltIn``. This method will only accept URIs that start with
     41 ``resource://`` and will give additional privileges like being able to use app
     42 messaging and not needing a signature.
     43 
     44 Each permission will have a machine readable name that the embedder will use to
     45 produce user-facing internationalized strings. E.g. “bookmarks” gives access to
     46 bookmarks, “sessions” gives access to recently closed sessions. The full list
     47 of permissions that are currently shown to the UI in Firefox Desktop is
     48 available at: ``toolkit/global/extensionPermissions.ftl``
     49 
     50 ``WebExtension.MetaData`` properties expected to be set to absolute moz-extension urls
     51 (e.g. ``baseUrl`` and ``optionsPageUrl``) are not available yet right after installing
     52 a new extension. Once the extension has been fully started, the delegate method
     53 ``WebExtensionController.AddonManagerDelegate.onReady`` will be providing to the
     54 embedder app a new instance of the `MetaData` object where ``baseUrl`` is expected
     55 to be set to a ``"moz-extension://..."`` url (and ``optionsPageUrl`` as well if an
     56 options page was declared in the extension manifest.json file).
     57 
     58 Updating
     59 ^^^^^^^^
     60 
     61 To update an extension, the embedder will be able to call update which will
     62 check if any update is available (using the update_url provided by the
     63 extension, or addons.mozilla.org if no update_url has been provided). The
     64 embedder will receive a GeckoResult that will provide the updated extension
     65 object. This result can also be used to know when the update process is
     66 complete, e.g. the embedder could use it to display a persistent notification
     67 to the user to avoid having the app be killed while updates are in process.
     68 
     69 If the updated extension needs additional permissions, ``GeckoView`` will call
     70 ``onUpdatePrompt``.
     71 
     72 Until this callback is resolved (i.e. the embedder’s returned ``GeckoResult``
     73 is completed), the old addon will be running, only when the prompt is resolved
     74 and the update is applied the new version of the addon starts running and the
     75 ``GeckoResult`` returned from update is resolved.
     76 
     77 This callback will provide both the current ``WebExtension`` object and the
     78 updated WebExtension object so that the embedder can show appropriate
     79 information to the user, e.g. the app might decide to remember whether the user
     80 denied the request for a certain version and only prompt the user once the
     81 version string changes.
     82 
     83 As a side effect of updating, Gecko will check its internal blocklist and might
     84 disable extensions that are incompatible with the current version of Gecko or
     85 deemed unsafe. The resulting ``WebExtension`` object will reflect that by
     86 having isEnabled set to false. The embedder will be able to inspect the reason
     87 why the extension was disabled using ``metaData.blockedReason``.
     88 
     89 Gecko will not update any extension or blocklist state without the embedder’s
     90 input.
     91 
     92 Enabling and Disabling
     93 ^^^^^^^^^^^^^^^^^^^^^^
     94 
     95 Embedders will be able to enable and disabling extension using the homonymous
     96 APIs. Calling enable on an extension might not actually enable it if the
     97 extension has been added to the Gecko blocklist. Embedders can check the value
     98 of ``metaData.blockedReason`` to display to the user whether the extension can
     99 actually be enabled or not. The returned WebExtension object will reflect the
    100 updated enablement state in isEnabled.
    101 
    102 Listing
    103 ^^^^^^^
    104 
    105 The embedder is expected to keep a collection of all available extensions using
    106 the result of install and update. To retrieve the extensions that are already
    107 installed the embedder will be able to use ``listInstalled`` which will
    108 asynchronously retrieve the full list of extensions. We recommend calling
    109 ``listInstalled`` every time the user is presented with the extension manager
    110 UI to ensure all information is up to date.
    111 
    112 Outline
    113 ^^^^^^^
    114 
    115 .. code:: java
    116 
    117  public class WebExtensionController {
    118    // Start the process of installing an extension,
    119    // the embedder will either get the installed extension
    120    // or an error
    121    GeckoResult<WebExtension> install(String uri);
    122 
    123    // Install a built-in WebExtension with privileged
    124    // permissions, uri must be resource://
    125    // Privileged WebExtensions have access to experiments
    126    // (i.e. they can run chrome code), don’t need signatures
    127    // and have access to native messaging to the app
    128    GeckoResult<WebExtension> installBuiltIn(String uri)
    129 
    130    GeckoResult<Void> uninstall(WebExtension extension);
    131 
    132    GeckoResult<WebExtension> enable(WebExtension extension);
    133 
    134    GeckoResult<WebExtension> disable(WebExtension extension);
    135 
    136    GeckoResult<List<WebExtension>> listInstalled();
    137 
    138    // Checks for updates. This method returns a GeckoResult that is
    139    // resolved either with the updated WebExtension object or null
    140    // if the extension does not have pending updates.
    141    GeckoResult<WebExtension> update(WebExtension extension);
    142 
    143    public interface PromptDelegate {
    144        GeckoResult<AllowOrDeny> onInstallPrompt(WebExtension extension);
    145 
    146        GeckoResult<AllowOrDeny> onUpdatePrompt(
    147            WebExtension currentlyInstalled,
    148            WebExtension updatedExtension,
    149            List<String> newPermissions);
    150 
    151        // Called when the extension calls browser.permission.request
    152        GeckoResult<AllowOrDeny> onOptionalPrompt(
    153            WebExtension extension,
    154            List<String> optionalPermissions);
    155    }
    156 
    157    void setPromptDelegate(PromptDelegate promptDelegate);
    158  }
    159 
    160 As part of this document, we will add a ``MetaData`` field to WebExtension
    161 which will contain all the information known about the extension. Note: we will
    162 rename ``ActionIcon`` to Icon to represent its generic use as the
    163 ``WebExtension`` icon class.
    164 
    165 .. code:: java
    166 
    167  public class WebExtension {
    168    // Renamed from ActionIcon
    169    static class Icon {}
    170 
    171    final MetaData metadata;
    172    final boolean isBuiltIn;
    173 
    174    final boolean isEnabled;
    175 
    176    public static class SignedStateFlags {
    177      final static int UNKNOWN;
    178      final static int PRELIMINARY;
    179      final static int SIGNED;
    180      final static int SYSTEM;
    181      final static int PRIVILEGED;
    182    }
    183 
    184    // See nsIBlocklistService.idl
    185    public static class BlockedReason {
    186      final static int NOT_BLOCKED;
    187      final static int SOFTBLOCKED;
    188      final static int BLOCKED;
    189      final static int OUTDATED;
    190      final static int VULNERABLE_UPDATE_AVAILABLE;
    191      final static int VULNERABLE_NO_UPDATE;
    192    }
    193 
    194    public class MetaData {
    195      final Icon icon;
    196      final String[] permissions;
    197      final String[] origins;
    198      final String name;
    199      final String description;
    200      final String version;
    201      final String creatorName;
    202      final String creatorUrl;
    203      final String homepageUrl;
    204      final String baseUrl;
    205      final String optionsPageUrl;
    206      final boolean openOptionsPageInTab;
    207      final boolean isRecommended;
    208      final @BlockedReason int blockedReason;
    209      final @SignedState int signedState;
    210      // more if needed
    211    }
    212  }
    213 
    214 Implementation Details
    215 ^^^^^^^^^^^^^^^^^^^^^^
    216 
    217 We will use ``AddonManager`` as a backend for ``WebExtensionController`` and
    218 delegate the prompt to the app using ``PromptDelegate``. We will also merge
    219 ``WebExtensionController`` and ``WebExtensionEventDispatcher`` for ease of
    220 implementation.
    221 
    222 Existing APIs
    223 ^^^^^^^^^^^^^
    224 
    225 Some APIs today return a ``WebExtension`` object that might have not been
    226 fetched yet by ``listInstalled``. In these cases, GeckoView will return a stub
    227 ``WebExtension`` object in which the metadata field will be null to avoid
    228 waiting for a addon list call. To ensure that the metadata field is populated,
    229 the embedder will need to call ``listInstalled`` at least once during the app
    230 startup.
    231 
    232 Deprecation Path
    233 ^^^^^^^^^^^^^^^^
    234 
    235 The existing ``registerWebExtension`` and ``unregisterWebExtension`` APIs will
    236 be deprecated by ``installBuiltIn`` and ``uninstall``. We will remove the above
    237 APIs 6 releases after the implementation of ``installBuiltIn`` lands and mark
    238 it as deprecated in the API.