mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +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> {
|
async fn get_password_new(service: &str, account: &str) -> Result<String> {
|
||||||
let keyring = oo7::Keyring::new().await?;
|
let keyring = oo7::Keyring::new().await?;
|
||||||
|
let _ = try_prompt(&keyring).await;
|
||||||
let attributes = HashMap::from([("service", service), ("account", account)]);
|
let attributes = HashMap::from([("service", service), ("account", account)]);
|
||||||
let results = keyring.search_items(&attributes).await?;
|
let results = keyring.search_items(&attributes).await?;
|
||||||
let res = results.first();
|
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 svc = dbus::Service::new().await?;
|
||||||
let collection = svc.default_collection().await?;
|
let collection = svc.default_collection().await?;
|
||||||
let keyring = oo7::Keyring::DBus(collection);
|
let keyring = oo7::Keyring::DBus(collection);
|
||||||
|
let _ = try_prompt(&keyring).await;
|
||||||
let attributes = HashMap::from([("service", service), ("account", account)]);
|
let attributes = HashMap::from([("service", service), ("account", account)]);
|
||||||
let results = keyring.search_items(&attributes).await?;
|
let results = keyring.search_items(&attributes).await?;
|
||||||
let res = results.first();
|
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<()> {
|
pub async fn set_password(service: &str, account: &str, password: &str) -> Result<()> {
|
||||||
let keyring = oo7::Keyring::new().await?;
|
let keyring = oo7::Keyring::new().await?;
|
||||||
|
let _ = try_prompt(&keyring).await;
|
||||||
let attributes = HashMap::from([("service", service), ("account", account)]);
|
let attributes = HashMap::from([("service", service), ("account", account)]);
|
||||||
keyring
|
keyring
|
||||||
.create_item(
|
.create_item(
|
||||||
@@ -62,13 +65,62 @@ pub async fn set_password(service: &str, account: &str, password: &str) -> Resul
|
|||||||
Ok(())
|
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<()> {
|
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 keyring = oo7::Keyring::new().await?;
|
||||||
let attributes = HashMap::from([("service", service), ("account", account)]);
|
let attributes = HashMap::from([("service", service), ("account", account)]);
|
||||||
keyring.delete(&attributes).await?;
|
keyring.delete(&attributes).await?;
|
||||||
Ok(())
|
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> {
|
pub async fn is_available() -> Result<bool> {
|
||||||
match oo7::Keyring::new().await {
|
match oo7::Keyring::new().await {
|
||||||
Ok(_) => Ok(true),
|
Ok(_) => Ok(true),
|
||||||
|
|||||||
Reference in New Issue
Block a user