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:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user