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