]> git.proxmox.com Git - rustc.git/blame - src/tools/cargo/credential/cargo-credential-macos-keychain/src/lib.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / src / tools / cargo / credential / cargo-credential-macos-keychain / src / lib.rs
CommitLineData
add651ee
FG
1//! Cargo registry macos keychain credential process.
2
4b012472
FG
3#![allow(clippy::print_stderr)]
4
add651ee
FG
5#[cfg(target_os = "macos")]
6mod macos {
7 use cargo_credential::{
8 read_token, Action, CacheControl, Credential, CredentialResponse, Error, RegistryInfo,
9 };
10 use security_framework::os::macos::keychain::SecKeychain;
11
12 pub struct MacKeychain;
13
14 /// The account name is not used.
15 const ACCOUNT: &'static str = "";
16 const NOT_FOUND: i32 = -25300; // errSecItemNotFound
17
18 fn registry(index_url: &str) -> String {
19 format!("cargo-registry:{}", index_url)
20 }
21
22 impl Credential for MacKeychain {
23 fn perform(
24 &self,
25 reg: &RegistryInfo<'_>,
26 action: &Action<'_>,
27 _args: &[&str],
28 ) -> Result<CredentialResponse, Error> {
29 let keychain = SecKeychain::default().unwrap();
30 let service_name = registry(reg.index_url);
31 let not_found = security_framework::base::Error::from(NOT_FOUND).code();
32 match action {
33 Action::Get(_) => match keychain.find_generic_password(&service_name, ACCOUNT) {
34 Err(e) if e.code() == not_found => Err(Error::NotFound),
35 Err(e) => Err(Box::new(e).into()),
36 Ok((pass, _)) => {
37 let token = String::from_utf8(pass.as_ref().to_vec()).map_err(Box::new)?;
38 Ok(CredentialResponse::Get {
39 token: token.into(),
40 cache: CacheControl::Session,
41 operation_independent: true,
42 })
43 }
44 },
45 Action::Login(options) => {
46 let token = read_token(options, reg)?;
47 match keychain.find_generic_password(&service_name, ACCOUNT) {
48 Err(e) => {
49 if e.code() == not_found {
50 keychain
51 .add_generic_password(
52 &service_name,
53 ACCOUNT,
54 token.expose().as_bytes(),
55 )
56 .map_err(Box::new)?;
57 }
58 }
59 Ok((_, mut item)) => {
60 item.set_password(token.expose().as_bytes())
61 .map_err(Box::new)?;
62 }
63 }
64 Ok(CredentialResponse::Login)
65 }
66 Action::Logout => match keychain.find_generic_password(&service_name, ACCOUNT) {
67 Err(e) if e.code() == not_found => Err(Error::NotFound),
68 Err(e) => Err(Box::new(e).into()),
69 Ok((_, item)) => {
70 item.delete();
71 Ok(CredentialResponse::Logout)
72 }
73 },
74 _ => Err(Error::OperationNotSupported),
75 }
76 }
77 }
78}
79
80#[cfg(not(target_os = "macos"))]
81pub use cargo_credential::UnsupportedCredential as MacKeychain;
82#[cfg(target_os = "macos")]
83pub use macos::MacKeychain;