diff options
Diffstat (limited to '')
-rw-r--r-- | crates/credential/cargo-credential-macos-keychain/Cargo.toml | 11 | ||||
-rw-r--r-- | crates/credential/cargo-credential-macos-keychain/src/main.rs | 50 |
2 files changed, 61 insertions, 0 deletions
diff --git a/crates/credential/cargo-credential-macos-keychain/Cargo.toml b/crates/credential/cargo-credential-macos-keychain/Cargo.toml new file mode 100644 index 0000000..c2c22a4 --- /dev/null +++ b/crates/credential/cargo-credential-macos-keychain/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cargo-credential-macos-keychain" +version = "0.2.0" +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/cargo" +description = "A Cargo credential process that stores tokens in a macOS keychain." + +[dependencies] +cargo-credential = { version = "0.2.0", path = "../cargo-credential" } +security-framework = "2.0.0" diff --git a/crates/credential/cargo-credential-macos-keychain/src/main.rs b/crates/credential/cargo-credential-macos-keychain/src/main.rs new file mode 100644 index 0000000..3fef3f9 --- /dev/null +++ b/crates/credential/cargo-credential-macos-keychain/src/main.rs @@ -0,0 +1,50 @@ +//! Cargo registry macos keychain credential process. + +use cargo_credential::{Credential, Error}; +use security_framework::os::macos::keychain::SecKeychain; + +struct MacKeychain; + +/// The account name is not used. +const ACCOUNT: &'static str = ""; + +fn registry(registry_name: &str) -> String { + format!("cargo-registry:{}", registry_name) +} + +impl Credential for MacKeychain { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result<String, Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + String::from_utf8(pass.as_ref().to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) + } + + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(name.unwrap_or(index_url)); + if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) { + item.set_password(token.as_bytes())?; + } else { + keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?; + } + Ok(()) + } + + fn erase(&self, index_url: &str) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + item.delete(); + Ok(()) + } +} + +fn main() { + cargo_credential::main(MacKeychain); +} |