/* 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; }; /// Metadata fields managed internally by the library. /// These are automatically set on `add()` and updated on operations like `touch()` and `update()`. /// Not included in LoginEntry; use `add_with_meta()` when importing records with existing metadata. dictionary LoginMeta { string id; i64 times_used; i64 time_created; i64 time_last_used; i64 time_password_changed; i64? time_of_last_breach; i64? time_last_breach_alert_dismissed; }; /// 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; // breach fields i64? time_of_last_breach; i64? time_last_breach_alert_dismissed; // 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); /// Determines whether a login’s password is potentially breached, based on the breach date and the time of the last password change. [Throws=LoginsApiError] boolean is_potentially_breached([ByRef] string id); /// Checks multiple logins for password reuse in a single batch operation. /// /// Returns the GUIDs of logins whose passwords match any password in the breach database. /// This is more efficient than calling `is_potentially_vulnerable_password()` repeatedly, /// as it decrypts the breach database only once. [Throws=LoginsApiError] sequence are_potentially_vulnerable_passwords(sequence ids); /// Checks if a login's password matches any password in the local breach database. /// /// Returns true if this login's password appears in the breachesL table, indicating /// that the same password has been breached on a different domain (password reuse). /// This is independent of whether this specific login has been marked as breached. [Throws=LoginsApiError] boolean is_potentially_vulnerable_password([ByRef] string id); /// Records a list of potentially vulnerable passwords in the breach database. /// /// This is used to bulk-populate the breachesL table with known breached passwords, /// typically during import operations or when syncing breach data. /// Passwords are encrypted before storage and duplicates are automatically filtered out. [Throws=LoginsApiError] void record_potentially_vulnerable_passwords(sequence passwords); /// Stores a known breach date for a login. /// In Firefox Desktop this is updated once per session from Remote Settings. [Throws=LoginsApiError] void record_breach([ByRef] string id, i64 timestamp); /// Removes all recorded breaches for all logins (i.e. sets time_of_last_breach to null). [Throws=LoginsApiError] void reset_all_breaches(); /// Determines whether a breach alert has been dismissed, based on the breach date and the alert dismissal timestamp. [Throws=LoginsApiError] boolean is_breach_alert_dismissed([ByRef] string id); /// Stores that the user dismissed the breach alert for a login. [Throws=LoginsApiError] void record_breach_alert_dismissal([ByRef] string id); /// Stores the time at which the user dismissed the breach alert for a login. [Throws=LoginsApiError] void record_breach_alert_dismissal_time([ByRef] string id, i64 timestamp); [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(); };