Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
### Logins
- expose constructors for `ManagedEncryptorDecryptor` and `NSSKeyManager`
- change PrimaryPasswordAuthenticator callbacks to be async (a breaking change, but not yet used by anyone)
- return Result in PrimaryPasswordAuthenticator callbacks (again a breaking change, but not yet used by anyone)
- add factory for login store with nss key manager: `create_login_store_with_nss_keymanager` to avoid round-tripping the KeyManager trait interface through JS.

# v141.0 (_2025-06-23_)

Expand Down
28 changes: 17 additions & 11 deletions components/logins/src/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ pub trait PrimaryPasswordAuthenticator: Send + Sync {
/// Get a primary password for authentication, otherwise return the
/// AuthenticationCancelled error to cancel the authentication process.
async fn get_primary_password(&self) -> ApiResult<String>;
async fn on_authentication_success(&self);
async fn on_authentication_failure(&self);
async fn on_authentication_success(&self) -> ApiResult<()>;
async fn on_authentication_failure(&self) -> ApiResult<()>;
}

/// Use the `NSSKeyManager` to use NSS for key management.
Expand All @@ -200,10 +200,10 @@ pub trait PrimaryPasswordAuthenticator: Send + Sync {
///
/// # Examples
/// ```no_run
/// use std::sync::Arc;
/// use async_trait::async_trait;
/// use logins::{PrimaryPasswordAuthenticator, LoginsApiError, NSSKeyManager};
/// use logins::encryption::KeyManager;
/// use logins::{PrimaryPasswordAuthenticator, LoginsApiError, NSSKeyManager};
/// use std::sync::Arc;
///
/// struct MyPrimaryPasswordAuthenticator {}
///
Expand All @@ -215,12 +215,14 @@ pub trait PrimaryPasswordAuthenticator: Send + Sync {
/// Ok("secret".to_string())
/// }
///
/// async fn on_authentication_success(&self) {
/// async fn on_authentication_success(&self) -> Result<(), LoginsApiError> {
/// println!("success");
/// Ok(())
/// }
///
/// async fn on_authentication_failure(&self) {
/// async fn on_authentication_failure(&self) -> Result<(), LoginsApiError> {
/// println!("this did not work, please try again:");
/// Ok(())
/// }
/// }
/// let key_manager = NSSKeyManager::new(Arc::new(MyPrimaryPasswordAuthenticator {}));
Expand Down Expand Up @@ -287,13 +289,13 @@ impl KeyManager for NSSKeyManager {
block_on(
self.primary_password_authenticator
.on_authentication_success(),
);
)?;
} else {
while !result {
block_on(
self.primary_password_authenticator
.on_authentication_failure(),
);
)?;

let primary_password =
block_on(self.primary_password_authenticator.get_primary_password())?;
Expand All @@ -302,7 +304,7 @@ impl KeyManager for NSSKeyManager {
block_on(
self.primary_password_authenticator
.on_authentication_success(),
);
)?;
}
}

Expand Down Expand Up @@ -464,8 +466,12 @@ mod keydb_test {
async fn get_primary_password(&self) -> ApiResult<String> {
Ok(self.password.clone())
}
async fn on_authentication_success(&self) {}
async fn on_authentication_failure(&self) {}
async fn on_authentication_success(&self) -> ApiResult<()> {
Ok(())
}
async fn on_authentication_failure(&self) -> ApiResult<()> {
Ok(())
}
}

fn profile_path() -> PathBuf {
Expand Down
8 changes: 8 additions & 0 deletions components/logins/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,11 @@ impl GetErrorHandling for Error {
}
}
}

impl From<uniffi::UnexpectedUniFFICallbackError> for LoginsApiError {
fn from(error: uniffi::UnexpectedUniFFICallbackError) -> Self {
LoginsApiError::UnexpectedLoginsApiError {
reason: error.to_string(),
}
}
}
16 changes: 16 additions & 0 deletions components/logins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,19 @@ pub fn create_login_store_with_static_key_manager(path: String, key: String) ->
ManagedEncryptorDecryptor::new(Arc::new(StaticKeyManager::new(key)));
Arc::new(LoginStore::new(path, Arc::new(encdec)).unwrap())
}

// Create a LoginStore with NSSKeyManager by passing in a db path and a PrimaryPasswordAuthenticator.
//
// Note this is only temporarily needed until a bug with UniFFI and JavaScript is fixed, which
// prevents passing around traits in JS
#[cfg(feature = "keydb")]
#[uniffi::export]
pub fn create_login_store_with_nss_keymanager(
path: String,
primary_password_authenticator: Arc<dyn PrimaryPasswordAuthenticator>,
) -> Arc<LoginStore> {
let encdec: ManagedEncryptorDecryptor = ManagedEncryptorDecryptor::new(Arc::new(
NSSKeyManager::new(primary_password_authenticator),
));
Arc::new(LoginStore::new(path, Arc::new(encdec)).unwrap())
}
3 changes: 2 additions & 1 deletion components/logins/src/logins.udl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ namespace logins {
/// ManagedEncryptorDecryptor by passing in a KeyManager
EncryptorDecryptor create_managed_encdec(KeyManager key_manager);

/// Create a LoginStore by passing in a db path and a static key
/// 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);
};

Expand Down
6 changes: 4 additions & 2 deletions examples/sync-pass/src/sync-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,14 @@ impl PrimaryPasswordAuthenticator for MyPrimaryPasswordAuthenticator {
Ok(password)
}

async fn on_authentication_success(&self) {
async fn on_authentication_success(&self) -> Result<(), LoginsApiError> {
println!("success");
Ok(())
}

async fn on_authentication_failure(&self) {
async fn on_authentication_failure(&self) -> Result<(), LoginsApiError> {
println!("this did not work, please try again:");
Ok(())
}
}

Expand Down