Use spawn_blocking in macos.rs async methods

This commit is contained in:
John Mumm 2025-08-12 11:43:59 +01:00
parent fe47f54c38
commit f79330abcb
No known key found for this signature in database
GPG Key ID: 73D2271AFDC26EA8
1 changed files with 68 additions and 21 deletions

View File

@ -56,9 +56,17 @@ impl CredentialApi for MacCredential {
/// Since there is only one credential with a given _account_ and _user_
/// in any given keychain, there is no chance of ambiguity.
async fn set_password(&self, password: &str) -> Result<()> {
get_keychain(self)?
.set_generic_password(&self.service, &self.account, password.as_bytes())
.map_err(decode_error)?;
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
let password = password.to_string();
tokio::task::spawn_blocking(move || {
get_keychain(domain)?
.set_generic_password(&service, &account, password.as_bytes())
.map_err(decode_error)
})
.await
.map_err(|e| ErrorCode::PlatformFailure(Box::new(e)))??;
Ok(())
}
@ -68,9 +76,17 @@ impl CredentialApi for MacCredential {
/// Since there is only one credential with a given _account_ and _user_
/// in any given keychain, there is no chance of ambiguity.
async fn set_secret(&self, secret: &[u8]) -> Result<()> {
get_keychain(self)?
.set_generic_password(&self.service, &self.account, secret)
.map_err(decode_error)?;
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
let secret = secret.to_vec();
tokio::task::spawn_blocking(move || {
get_keychain(domain)?
.set_generic_password(&service, &account, &secret)
.map_err(decode_error)
})
.await
.map_err(|e| ErrorCode::PlatformFailure(Box::new(e)))??;
Ok(())
}
@ -79,10 +95,20 @@ impl CredentialApi for MacCredential {
/// Returns a [`NoEntry`](ErrorCode::NoEntry) error if there is no
/// credential in the store.
async fn get_password(&self) -> Result<String> {
let (password_bytes, _) =
find_generic_password(Some(&[get_keychain(self)?]), &self.service, &self.account)
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
let password_bytes = tokio::task::spawn_blocking(move || -> Result<Vec<u8>> {
let keychain = get_keychain(domain)?;
let (password_bytes, _) = find_generic_password(Some(&[keychain]), &service, &account)
.map_err(decode_error)?;
decode_password(password_bytes.to_owned())
Ok(password_bytes.to_owned())
})
.await
.map_err(|e| ErrorCode::PlatformFailure(Box::new(e)))??;
decode_password(password_bytes)
}
/// Look up the secret for this entry, if any.
@ -90,10 +116,20 @@ impl CredentialApi for MacCredential {
/// Returns a [`NoEntry`](ErrorCode::NoEntry) error if there is no
/// credential in the store.
async fn get_secret(&self) -> Result<Vec<u8>> {
let (password_bytes, _) =
find_generic_password(Some(&[get_keychain(self)?]), &self.service, &self.account)
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
let password_bytes = tokio::task::spawn_blocking(move || -> Result<Vec<u8>> {
let keychain = get_keychain(domain)?;
let (password_bytes, _) = find_generic_password(Some(&[keychain]), &service, &account)
.map_err(decode_error)?;
Ok(password_bytes.to_owned())
Ok(password_bytes.to_owned())
})
.await
.map_err(|e| ErrorCode::PlatformFailure(Box::new(e)))??;
Ok(password_bytes)
}
/// Delete the underlying generic credential for this entry, if any.
@ -101,10 +137,19 @@ impl CredentialApi for MacCredential {
/// Returns a [`NoEntry`](ErrorCode::NoEntry) error if there is no
/// credential in the store.
async fn delete_credential(&self) -> Result<()> {
let (_, item) =
find_generic_password(Some(&[get_keychain(self)?]), &self.service, &self.account)
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
tokio::task::spawn_blocking(move || {
let keychain = get_keychain(domain)?;
let (_, item) = find_generic_password(Some(&[keychain]), &service, &account)
.map_err(decode_error)?;
item.delete();
item.delete();
Ok(())
})
.await
.map_err(|e| ErrorCode::PlatformFailure(Box::new(e)))??;
Ok(())
}
@ -127,9 +172,11 @@ impl MacCredential {
/// other than the ones we use to find the generic credential.
/// But at least this checks whether the underlying credential exists.
pub fn get_credential(&self) -> Result<Self> {
let (_, _) =
find_generic_password(Some(&[get_keychain(self)?]), &self.service, &self.account)
.map_err(decode_error)?;
let service = self.service.clone();
let account = self.account.clone();
let domain = self.domain;
let (_, _) = find_generic_password(Some(&[get_keychain(domain)?]), &service, &account)
.map_err(decode_error)?;
Ok(self.clone())
}
@ -209,7 +256,7 @@ impl CredentialBuilderApi for MacCredentialBuilder {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// The four pre-defined Mac keychains.
pub enum MacKeychainDomain {
User,
@ -255,8 +302,8 @@ impl std::str::FromStr for MacKeychainDomain {
}
}
fn get_keychain(cred: &MacCredential) -> Result<SecKeychain> {
let domain = match cred.domain {
fn get_keychain(domain: MacKeychainDomain) -> Result<SecKeychain> {
let domain = match domain {
MacKeychainDomain::User => SecPreferencesDomain::User,
MacKeychainDomain::System => SecPreferencesDomain::System,
MacKeychainDomain::Common => SecPreferencesDomain::Common,