/* 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/. */ namespace logins { /// We expose the crypto primitives on the namespace /// Create a new, random, encryption key. [Throws=LoginsApiError] string create_key(); /// Create a "canary" string, which can be used to test if the encryption //key is still valid for the logins data [Throws=LoginsApiError] string create_canary([ByRef]string text, [ByRef]string encryption_key); /// Check that key is still valid using the output of `create_canary`. //`text` much match the text you initially passed to `create_canary()` [Throws=LoginsApiError] boolean check_canary([ByRef]string canary, [ByRef]string text, [ByRef]string encryption_key); /// Utility function to create a StaticKeyManager to be used for the time /// being until support lands for [trait implementation of an UniFFI /// interface](https://mozilla.github.io/uniffi-rs/next/proc_macro/index.html#structs-implementing-traits) /// in UniFFI. KeyManager create_static_key_manager(string key); /// Similar to create_static_key_manager above, create a /// ManagedEncryptorDecryptor by passing in a KeyManager EncryptorDecryptor create_managed_encdec(KeyManager key_manager); /// Create a LoginStore with StaticKeyManager by passing in a db path and a /// static key LoginStore create_login_store_with_static_key_manager(string path, string key); }; /// A login entry from the user, not linked to any database record. /// The add/update APIs input these. dictionary LoginEntry { // login fields string origin; string? http_realm; string? form_action_origin; string username_field; string password_field; // secure login fields string password; string username; }; /// Login data specific to database records. /// The add_with_record API inputs this. dictionary LoginMeta { string id; i64 times_used; i64 time_created; i64 time_last_used; i64 time_password_changed; }; /// A login together with record fields, handed over to the store API; ie a login persisted /// elsewhere, useful for migrations dictionary LoginEntryWithMeta { LoginEntry entry; LoginMeta meta; }; /// A bulk insert result entry, returned by `add_many` and `add_many_with_meta` [Enum] interface BulkResultEntry { Success(Login login); Error(string message); }; /// A login stored in the database dictionary Login { // meta fields string id; i64 times_used; i64 time_created; i64 time_last_used; i64 time_password_changed; // login fields string origin; string? http_realm; string? form_action_origin; string username_field; string password_field; // secure login fields string password; string username; }; /// Metrics tracking deletion of logins that cannot be decrypted, see `delete_undecryptable_records_for_remote_replacement` /// for more details dictionary LoginsDeletionMetrics { u64 local_deleted; u64 mirror_deleted; }; /// These are the errors returned by our public API. [Error] interface LoginsApiError { /// NSS not initialized. NSSUninitialized(); /// NSS error during authentication NSSAuthenticationError(string reason); /// error during authentication (in PrimaryPasswordAuthenticator) AuthenticationError(string reason); /// authentication has been cancelled. AuthenticationCanceled(); /// The login data supplied is invalid. The reason will indicate what's wrong with it. InvalidRecord(string reason); /// Asking to do something with a guid which doesn't exist. NoSuchRecord(string reason); /// Encryption key is missing. MissingKey(); /// Encryption key is not valid. InvalidKey(); /// encryption failed EncryptionFailed(string reason); /// decryption failed DecryptionFailed(string reason); /// An operation was interrupted at the request of the consuming app. Interrupted(string reason); /// Sync reported that authentication failed and the user should re-enter their FxA password. // TODO: remove this at the same time as remove the sync() method in favour of the SyncManager. SyncAuthInvalid(string reason); /// something internal went wrong which doesn't have a public error value /// because the consuming app can not reasonably take any action to resolve it. /// The underlying error will have been logged and reported. /// (ideally would just be `Unexpected`, but that would be a breaking change) UnexpectedLoginsApiError(string reason); }; [Trait, WithForeign] interface EncryptorDecryptor { [Throws=LoginsApiError] bytes encrypt(bytes cleartext); [Throws=LoginsApiError] bytes decrypt(bytes ciphertext); }; [Trait, WithForeign] interface KeyManager { [Throws=LoginsApiError] bytes get_key(); }; interface StaticKeyManager { constructor(string key); }; interface ManagedEncryptorDecryptor { constructor(KeyManager key_manager); }; interface LoginStore { [Throws=LoginsApiError] constructor(string path, EncryptorDecryptor encdec); [Throws=LoginsApiError] Login add(LoginEntry login); [Throws=LoginsApiError] sequence add_many(sequence logins); [Throws=LoginsApiError] Login add_with_meta(LoginEntryWithMeta entry_with_meta); [Throws=LoginsApiError] sequence add_many_with_meta(sequence entries_with_meta); [Throws=LoginsApiError] Login update([ByRef] string id, LoginEntry login); [Throws=LoginsApiError] Login add_or_update(LoginEntry login); [Throws=LoginsApiError] boolean delete([ByRef] string id); [Throws=LoginsApiError, Self=ByArc] sequence delete_many(sequence ids); /// Clear out locally stored logins data /// /// If sync is enabled, then we will try to recover the data on the next sync. /// /// The main reason to call this is when regenerating a new encryption key. /// In that case, there's no reason to keep around the local data since it can't be decrypted. /// Calling `wipe_local` is better than keeping around these un-decryptable logins, since we /// might be able to recover the data via sync. /// /// This is a no-op for freshly created databases, so it's safe to call this whenever a key is /// generated. [Throws=LoginsApiError] void wipe_local(); [Throws=LoginsApiError, Self=ByArc] void reset(); /// The `delete_undecryptable_records_for_remote_replacement` function locally deletes stored logins /// that cannot be decrypted and sets the last sync time to 0 so any existing server records can be downloaded /// and overwrite the locally deleted records. /// /// NB: This function was created to unblock iOS logins users who are unable to sync logins and should not be used /// outside of this use case. [Throws=LoginsApiError, Self=ByArc] LoginsDeletionMetrics delete_undecryptable_records_for_remote_replacement(); [Throws=LoginsApiError] void touch([ByRef] string id); [Throws=LoginsApiError] boolean is_empty(); [Throws=LoginsApiError] i64 count(); [Throws=LoginsApiError] i64 count_by_origin([ByRef] string origin); [Throws=LoginsApiError] i64 count_by_form_action_origin([ByRef] string form_action_origin); [Throws=LoginsApiError] sequence list(); [Throws=LoginsApiError] sequence get_by_base_domain([ByRef] string base_domain); [Throws=LoginsApiError] boolean has_logins_by_base_domain([ByRef] string base_domain); [Throws=LoginsApiError] Login? find_login_to_update(LoginEntry look); [Throws=LoginsApiError] Login? get([ByRef] string id); [Throws=LoginsApiError] void set_checkpoint([ByRef] string checkpoint); [Throws=LoginsApiError] string? get_checkpoint(); /// Run maintenance on the DB /// /// This is intended to be run during idle time and will take steps / to clean up / shrink the /// database. [Throws=LoginsApiError] void run_maintenance(); [Self=ByArc] void register_with_sync_manager(); [Self=ByArc] void shutdown(); };