diff --git a/crates/credential/cargo-credential-wincred/src/main.rs b/crates/credential/cargo-credential-wincred/src/main.rs index 8ae48f34899..4f848611d10 100644 --- a/crates/credential/cargo-credential-wincred/src/main.rs +++ b/crates/credential/cargo-credential-wincred/src/main.rs @@ -1,111 +1,116 @@ //! Cargo registry windows credential process. -use cargo_credential::{Credential, Error}; -use std::ffi::OsStr; -use std::os::windows::ffi::OsStrExt; +mod win { + use cargo_credential::{Credential, Error}; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; -use windows_sys::core::PWSTR; -use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; -use windows_sys::Win32::Foundation::FILETIME; -use windows_sys::Win32::Foundation::TRUE; -use windows_sys::Win32::Security::Credentials::CredDeleteW; -use windows_sys::Win32::Security::Credentials::CredReadW; -use windows_sys::Win32::Security::Credentials::CredWriteW; -use windows_sys::Win32::Security::Credentials::CREDENTIALW; -use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; -use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; + use windows_sys::core::PWSTR; + use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; + use windows_sys::Win32::Foundation::FILETIME; + use windows_sys::Win32::Foundation::TRUE; + use windows_sys::Win32::Security::Credentials::CredDeleteW; + use windows_sys::Win32::Security::Credentials::CredReadW; + use windows_sys::Win32::Security::Credentials::CredWriteW; + use windows_sys::Win32::Security::Credentials::CREDENTIALW; + use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; + use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; -struct WindowsCredential; + pub(crate) struct WindowsCredential; -/// Converts a string to a nul-terminated wide UTF-16 byte sequence. -fn wstr(s: &str) -> Vec { - let mut wide: Vec = OsStr::new(s).encode_wide().collect(); - if wide.iter().any(|b| *b == 0) { - panic!("nul byte in wide string"); + /// Converts a string to a nul-terminated wide UTF-16 byte sequence. + fn wstr(s: &str) -> Vec { + let mut wide: Vec = OsStr::new(s).encode_wide().collect(); + if wide.iter().any(|b| *b == 0) { + panic!("nul byte in wide string"); + } + wide.push(0); + wide } - wide.push(0); - wide -} -fn target_name(registry_name: &str) -> Vec { - wstr(&format!("cargo-registry:{}", registry_name)) -} - -impl Credential for WindowsCredential { - fn name(&self) -> &'static str { - env!("CARGO_PKG_NAME") + fn target_name(registry_name: &str) -> Vec { + wstr(&format!("cargo-registry:{}", registry_name)) } - fn get(&self, index_url: &str) -> Result { - let target_name = target_name(index_url); - let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; - unsafe { - if CredReadW( - target_name.as_ptr(), - CRED_TYPE_GENERIC, - 0, - p_credential as *mut _ as *mut _, - ) != TRUE - { - return Err( - format!("failed to fetch token: {}", std::io::Error::last_os_error()).into(), + impl Credential for WindowsCredential { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result { + let target_name = target_name(index_url); + let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; + unsafe { + if CredReadW( + target_name.as_ptr(), + CRED_TYPE_GENERIC, + 0, + p_credential as *mut _ as *mut _, + ) != TRUE + { + return Err(format!( + "failed to fetch token: {}", + std::io::Error::last_os_error() + ) + .into()); + } + let bytes = std::slice::from_raw_parts( + (*p_credential).CredentialBlob, + (*p_credential).CredentialBlobSize as usize, ); + String::from_utf8(bytes.to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) } - let bytes = std::slice::from_raw_parts( - (*p_credential).CredentialBlob, - (*p_credential).CredentialBlobSize as usize, - ); - String::from_utf8(bytes.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 token = token.as_bytes(); - let target_name = target_name(index_url); - let comment = match name { - Some(name) => wstr(&format!("Cargo registry token for {}", name)), - None => wstr("Cargo registry token"), - }; - let mut credential = CREDENTIALW { - Flags: 0, - Type: CRED_TYPE_GENERIC, - TargetName: target_name.as_ptr() as PWSTR, - Comment: comment.as_ptr() as PWSTR, - LastWritten: FILETIME { - dwLowDateTime: 0, - dwHighDateTime: 0, - }, - CredentialBlobSize: token.len() as u32, - CredentialBlob: token.as_ptr() as *mut u8, - Persist: CRED_PERSIST_LOCAL_MACHINE, - AttributeCount: 0, - Attributes: std::ptr::null_mut(), - TargetAlias: std::ptr::null_mut(), - UserName: std::ptr::null_mut(), - }; - let result = unsafe { CredWriteW(&mut credential, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - return Err(format!("failed to store token: {}", err).into()); + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let token = token.as_bytes(); + let target_name = target_name(index_url); + let comment = match name { + Some(name) => wstr(&format!("Cargo registry token for {}", name)), + None => wstr("Cargo registry token"), + }; + let mut credential = CREDENTIALW { + Flags: 0, + Type: CRED_TYPE_GENERIC, + TargetName: target_name.as_ptr() as PWSTR, + Comment: comment.as_ptr() as PWSTR, + LastWritten: FILETIME { + dwLowDateTime: 0, + dwHighDateTime: 0, + }, + CredentialBlobSize: token.len() as u32, + CredentialBlob: token.as_ptr() as *mut u8, + Persist: CRED_PERSIST_LOCAL_MACHINE, + AttributeCount: 0, + Attributes: std::ptr::null_mut(), + TargetAlias: std::ptr::null_mut(), + UserName: std::ptr::null_mut(), + }; + let result = unsafe { CredWriteW(&mut credential, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + return Err(format!("failed to store token: {}", err).into()); + } + Ok(()) } - Ok(()) - } - fn erase(&self, index_url: &str) -> Result<(), Error> { - let target_name = target_name(index_url); - let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { - eprintln!("not currently logged in to `{}`", index_url); - return Ok(()); + fn erase(&self, index_url: &str) -> Result<(), Error> { + let target_name = target_name(index_url); + let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { + eprintln!("not currently logged in to `{}`", index_url); + return Ok(()); + } + return Err(format!("failed to remove token: {}", err).into()); } - return Err(format!("failed to remove token: {}", err).into()); + Ok(()) } - Ok(()) } } fn main() { - cargo_credential::main(WindowsCredential); + cargo_credential::main(win::WindowsCredential); }