application-services/components/webext-storage/README.md

4.7 KiB

WebExtension Storage Component

The WebExtension Storage component can be used to power an implementation of the chrome.storage.sync WebExtension API, which gives each WebExtensions its own private key-value store that will sync between a user's devices. This particular implementation sits atop Firefox Sync.

With a small amount of work, this component would also be capable of powering an implementation of chrome.storage.local, but this is not an explicit goal at this stage.

Features

The WebExtension Storage component offers:

  1. Local storage of key-value data indexed by WebExtension ID.
  2. Basic Create, Read, Update and Delete (CRUD) operations for items in the database.
  3. Syncing of stored data between applications, via Firefox Sync.

The component does not offer, but may offer in the future:

  1. Separate storage for key-value data that does not sync, per the chrome.storage.local WebExtension API.
  2. Import functionality from previous WebExtension storage implementations backed by Kinto.

The component does not offer, and we have no concrete plans to offer:

  1. Any facilities for loading or running WebExtensions, or exposing this data to them.
  2. Any helpers to secure data access between different WebExtensions.

As a consuming application, you will need to implement code that plumbs this component in to your WebExtensions infrastructure, so that each WebExtension gets access to its own data (and only its own data) stored in this component.

Using the component

Prerequisites

To use this component for local storage of WebExtension data, you will need to know how to integrate appservices components into an application on your target platform:

  • Firefox Desktop: There's some custom bridging code in mozilla-central.
  • Android: Bindings not yet available; please reach out on slack to discuss!
  • iOS: Bindings not yet available; please reach out on slack to discuss!
  • Other Platforms: We don't know yet; please reach out on slack to discuss!

Core Concepts

  • We assume each WebExtension is uniquely identified by an immutable extension id.
  • A WebExtenstion Store is a database that maps extension ids to key-value JSON maps, one per extension. It exposes methods that mirror those of the chrome.storage spec (e.g. get, set, and delete) and which take an extension id as their first argument.

Working on the component

Prerequisites

To effectively work on the WebExtension Storage component, you will need to be familiar with:

Storage Overview

This component stores WebExtension data in a SQLite database, one row per extension id. The key-value map data for each extension is stored as serialized JSON in a TEXT field; this is nice and simple and helps ensure that the stored data has the semantics we want, which are pretty much just the semantics of JSON.

For syncing, we maintain a "mirror" table which contains one item per record known to exist on the server. These items are identified by a randomly-generated GUID, in order to hide the raw extension ids from the sync server.

When uploading records to the server, we write one encrypted BSO per extension. Its server-visible id is the randomly-generated GUID, and its encrypted payload contains the plaintext extension id and corresponding key-value map data.

The end result is something like this (highly simplified!) diagram:

storage overview diagram

The details of the encryption are handled by the sync15 crate, following the formats defied in sync storage format v5.