1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

Fix falling back to data.json when keyring is available (#12760)

* fix: fallback to data.json on Linux

* fix: make keyring prompt more consistent for reads+writes, but less assertive when we delete credentials

* fix: explicitly ignore unused return value
This commit is contained in:
tangowithfoxtrot
2025-02-21 07:44:24 -08:00
committed by GitHub
parent 1587f84a5c
commit b86e587507

View File

@@ -11,6 +11,7 @@ pub async fn get_password(service: &str, account: &str) -> Result<String> {
async fn get_password_new(service: &str, account: &str) -> Result<String> {
let keyring = oo7::Keyring::new().await?;
let _ = try_prompt(&keyring).await;
let attributes = HashMap::from([("service", service), ("account", account)]);
let results = keyring.search_items(&attributes).await?;
let res = results.first();
@@ -29,6 +30,7 @@ async fn get_password_legacy(service: &str, account: &str) -> Result<String> {
let svc = dbus::Service::new().await?;
let collection = svc.default_collection().await?;
let keyring = oo7::Keyring::DBus(collection);
let _ = try_prompt(&keyring).await;
let attributes = HashMap::from([("service", service), ("account", account)]);
let results = keyring.search_items(&attributes).await?;
let res = results.first();
@@ -50,6 +52,7 @@ async fn get_password_legacy(service: &str, account: &str) -> Result<String> {
pub async fn set_password(service: &str, account: &str, password: &str) -> Result<()> {
let keyring = oo7::Keyring::new().await?;
let _ = try_prompt(&keyring).await;
let attributes = HashMap::from([("service", service), ("account", account)]);
keyring
.create_item(
@@ -62,13 +65,62 @@ pub async fn set_password(service: &str, account: &str, password: &str) -> Resul
Ok(())
}
/// Remove a credential from the OS keyring. This function will *not* automatically
/// prompt the user to unlock their keyring. If the keyring is locked when this
/// is called, it will fail silently.
pub async fn delete_password(service: &str, account: &str) -> Result<()> {
// We need to silently fail in the event that the user's keyring was
// locked while our application was in-use. Otherwise, when we
// force a de-auth because we can't access keys in secure storage,
// kwallet will notify the user that an application is "misbehaving". This
// seems to happen because we call [delete_password] many times when a forced
// de-auth occurs to clean up old keys.
if is_locked().await? {
println!("skipping deletion of old keys. OS keyring is locked.");
return Ok(());
}
let keyring = oo7::Keyring::new().await?;
let attributes = HashMap::from([("service", service), ("account", account)]);
keyring.delete(&attributes).await?;
Ok(())
}
/// Sends an OS notification prompt for the user to unlock/allow the application
/// to read and write keys.
async fn try_prompt(keyring: &oo7::Keyring) -> bool {
keyring.unlock().await.is_ok()
}
/// Keyrings on Linux cannnot be assumed to be unlocked while the user is
/// logged in to a desktop session. Therefore, before reading or writing
/// keys, you should check if the keyring is unlocked, and call
/// [try_prompt] if ignoring the lock state is not an option.
pub async fn is_locked() -> Result<bool> {
let keyring = oo7::Keyring::new().await?;
// No simple way to check keyring lock state, so we just try to list items
let items = keyring.items().await?;
if let Some(item) = items.first() {
return match item.is_locked().await {
Ok(is_locked) => {
println!("OS keyring is locked = {is_locked}");
Ok(is_locked)
}
Err(_) => {
println!("OS keyring is unlocked");
Ok(false)
}
};
}
// assume it's locked
Ok(true)
}
/// This will return true if a keyring is configured. However, on Linux, it does
/// NOT indicate if the keyring is _unlocked_. Use [is_locked] to check
/// the lock state before reading or writing keys.
pub async fn is_available() -> Result<bool> {
match oo7::Keyring::new().await {
Ok(_) => Ok(true),