8 releases (5 major breaking)
128.0.1 | Jul 8, 2024 |
---|---|
127.0.1 | May 30, 2024 |
125.0.1 | Mar 28, 2024 |
123.0.1 | Feb 1, 2024 |
120.0.2 | Nov 29, 2023 |
#1888 in Database interfaces
626 stars & 47 watchers
265KB
5.5K
SLoC
Logins Component
The Logins component can be used to store website logins (i.e. usernames, passwords, and related metadata) and to sync them between applications using Firefox Sync.
Features
The Logins component offers:
- Local encrypted storage of login records (including usernames, passwords, and website metadata).
- Basic Create, Read, Update and Delete (CRUD) operations for login data.
- Syncing of logins data between applications, via Firefox Sync.
- Import functionality from existing login storage (ex: Fx Desktop or Fennec).
- Data migration functionality from Fennec to Firefox Preview storage.
The Logins component does not offer, and we have no concrete plans to offer:
- Any form-autofill of other UI-level functionality.
- Storage of other secret data, such as credit card numbers.
If you'd like to see new capabilities added to this component, please file an issue for discussion, but on the understanding that it may be a lengthy discussion.
Using the Logins component
Before using this component
Products sending telemetry and using this component must request a data-review following this process. This component provides data collection using the Glean SDK. The list of metrics being collected is available in the metrics documentation.
Prerequisites
To use this component for local storage of logins data, you will need to know how to integrate appservices components into an application on your target platform:
- Android: integrate via the sync-logins component from android-components.
- iOS: start with the guide to consuming rust components on iOS.
- Other Platforms: we don't know yet; please reach out on slack to discuss!
To sync logins data between devices, you will additionally need to integrate the FxAClient component in order to obtain the necessary user credentials and encryption keys, and the SyncManager component in order to orchestrate the syncing process.
Core Concepts
- A login record contains a single saved password along with other metadata about where it should be used. Each record is uniquely identified by an opaque string id, and contains fields such as username, password and origin. You can read about the fields on a login record in the code here.
- A logins store is a syncable encrypted database containing login records. In order to use the logins store,
the application must first unlock it by providing a secret key (preferably obtained from an OS-level keystore
mechanism). It can then create, read, update and delete login records from the database.
- If the application is connected to Firefox Sync, it can instruct the store to sync itself with the user's server-side logins data. This will upload any local modifications as well as download any new logins data from the server, automatically reconciling records in the case of conflict.
Examples
API Documentation
Working on the Logins component
Prerequisites
To effectively work on the Logins component, you will need to be familiar with:
- Our general guidelines for contributors.
- The core concepts for users of the component, outlined above.
- The way we generate ffi bindings and expose them to Kotlin and Swift.
- The key ideas behind how Firefox Sync works and the sync15 crate.
Implementation Overview
Logins implements encrypted storage for login records on top of a consumer implemented EncryptorDecryptor, or via ManagedEncryptorDecryptor, using NSS based crypto algorithms (AES256-GCM). The storage schema is based on the one originally used in Firefox for iOS, but with the following notable differences:
- the queries; they've been substantially modified for our needs here.
- how sync is performed; the version here allows syncs to complete with fewer database operations.
- timestamps; iOS uses microseconds, where the Logins component uses milliseconds.
See the header comment in src/schema.rs
for an overview of the schema.
Directory structure
The relevant directories are as follows:
src
: The meat of the library. This contains cross-platform rust code that implements the actual storage and sync of login records.examples
: This contains example rust code that implements a command-line app for syncing, displaying, and editing logins using the code insrc
. You can run it via cargo like so:cargo run --example sync_pass_sql
.ffi
: The Rust public FFI bindings. This is a (memory-unsafe, by necessity) API that is exposed to Kotlin and Swift. It leverages theffi_support
crate to avoid many issues and make it more safe than it otherwise would be. At the time of this writing, it uses JSON for marshalling data over the FFI, however in the future we will likely use protocol buffers.android
: This contains android bindings to logins, written in Kotlin. These use JNA to call into to the code inffi
.ios
: This contains the iOS binding to logins, written in Swift. These use Swift's native support for calling code written in C to call into the code inffi
.
Business Logic
Record storage
At any given time records can exist in 3 places, the local storage, the remote record, and the shared parent. The shared parent refers to a record that has been synced previously and is referred to in the code as the mirror. Login records are encrypted and stored locally. For any record that does not have a shared parent the login component tracks that the record has never been synced.
Reference the Logins chapter of the synconomicon for detailed information on the record storage format.
Sign-out behavior
When the user signs out of their Firefox Account, we reset the storage and clear the shared parent.
Merging records
When records are added, the logins component performs a three-way merge between the local record, the remote record and the shared parent (last update on the server). Details on the merging algorithm are contained in the generic sync rfc.
Record de-duplication
De-duplication compares the records for same the username and same url, but with different passwords. Deduplication logic is based on age, the username and hostname:
- If the changes are more recent than the local record it performs an update.
- If the change is older than our local records, and you have changed the same field on both, the record is not updated.
Testing
Our goal is to seek an acceptable level of test coverage. When making changes in an area, make an effort to improve (or minimally not reduce) coverage. Test coverage assessment includes:
Telemetry
Dependencies
~33MB
~539K SLoC