security-rs 0.2.0

Safe Rust bindings for Apple's Security framework — keychain, identity, certificates, trust, authorization, CMS, SecureTransport, and cryptographic primitives on macOS
Documentation
use crate::bridge;
use crate::error::Result;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeychainEntry {
    account: String,
    service: String,
}

impl KeychainEntry {
    pub fn new(account: impl Into<String>, service: impl Into<String>) -> Self {
        Self {
            account: account.into(),
            service: service.into(),
        }
    }

    pub fn account(&self) -> &str {
        &self.account
    }

    pub fn service(&self) -> &str {
        &self.service
    }

    pub fn set(&self, password: &str) -> Result<()> {
        Keychain::set(&self.account, &self.service, password)
    }

    pub fn get(&self) -> Result<String> {
        Keychain::get(&self.account, &self.service)
    }

    pub fn delete(&self) -> Result<()> {
        Keychain::delete(&self.account, &self.service)
    }
}

pub struct Keychain;

impl Keychain {
    pub fn entry(account: impl Into<String>, service: impl Into<String>) -> KeychainEntry {
        KeychainEntry::new(account, service)
    }

    pub fn set(account: &str, service: &str, password: &str) -> Result<()> {
        let account = bridge::cstring(account)?;
        let service = bridge::cstring(service)?;
        let password = bridge::cstring(password)?;
        let mut error = std::ptr::null_mut();
        let status = unsafe {
            bridge::security_keychain_set_password(
                account.as_ptr(),
                service.as_ptr(),
                password.as_ptr(),
                &mut error,
            )
        };
        bridge::status_result("security_keychain_set_password", status, error)
    }

    pub fn get(account: &str, service: &str) -> Result<String> {
        let account = bridge::cstring(account)?;
        let service = bridge::cstring(service)?;
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_keychain_get_password(
                account.as_ptr(),
                service.as_ptr(),
                &mut status,
                &mut error,
            )
        };
        bridge::required_string("security_keychain_get_password", raw, status, error)
    }

    pub fn delete(account: &str, service: &str) -> Result<()> {
        let account = bridge::cstring(account)?;
        let service = bridge::cstring(service)?;
        let mut error = std::ptr::null_mut();
        let status = unsafe {
            bridge::security_keychain_delete_password(account.as_ptr(), service.as_ptr(), &mut error)
        };
        bridge::status_result("security_keychain_delete_password", status, error)
    }

    pub fn list_accounts(service: &str) -> Result<Vec<String>> {
        let service = bridge::cstring(service)?;
        let mut status = 0;
        let mut error = std::ptr::null_mut();
        let raw = unsafe {
            bridge::security_keychain_list_accounts(service.as_ptr(), &mut status, &mut error)
        };
        bridge::required_json("security_keychain_list_accounts", raw, status, error)
    }
}