#![allow(
dead_code,
unused_imports,
unused_qualifications,
unreachable_patterns,
unsafe_code,
clippy::ptr_as_ptr
)]
use crate::internal::core::{Error, Result};
use windows::core::PCWSTR;
use windows::Win32::Foundation::{ERROR_NOT_FOUND, FILETIME};
use windows::Win32::Security::Credentials::{
CredDeleteW, CredFree, CredReadW, CredWriteW, CREDENTIALW, CRED_PERSIST_LOCAL_MACHINE,
CRED_TYPE_GENERIC,
};
const MARKER_PAYLOAD: &[u8] = b"v1";
fn target_name_wide(app_name: &str) -> Vec<u16> {
format!("com.godaddy.{app_name}.migrate-marker")
.encode_utf16()
.chain(std::iter::once(0))
.collect()
}
pub fn is_set(app_name: &str) -> Result<bool> {
let target = target_name_wide(app_name);
let mut cred_ptr: *mut CREDENTIALW = std::ptr::null_mut();
let result = unsafe { CredReadW(PCWSTR(target.as_ptr()), CRED_TYPE_GENERIC, 0, &mut cred_ptr) };
match result {
Ok(()) => {
if !cred_ptr.is_null() {
unsafe { CredFree(cred_ptr as *const _) };
}
Ok(true)
}
Err(e) => {
if e.code() == ERROR_NOT_FOUND.to_hresult() {
Ok(false)
} else {
Err(Error::KeyOperation {
operation: "migrate_marker_load".into(),
detail: format!("CredReadW: {e}"),
})
}
}
}
}
pub fn set(app_name: &str) -> Result<()> {
let mut target = target_name_wide(app_name);
let mut blob = MARKER_PAYLOAD.to_vec();
let blob_size = u32::try_from(blob.len()).map_err(|_| Error::KeyOperation {
operation: "migrate_marker_set".into(),
detail: "payload too large".into(),
})?;
let credential = CREDENTIALW {
Flags: windows::Win32::Security::Credentials::CRED_FLAGS(0),
Type: CRED_TYPE_GENERIC,
TargetName: windows::core::PWSTR(target.as_mut_ptr()),
Comment: windows::core::PWSTR::null(),
LastWritten: FILETIME::default(),
CredentialBlobSize: blob_size,
CredentialBlob: blob.as_mut_ptr(),
Persist: CRED_PERSIST_LOCAL_MACHINE,
AttributeCount: 0,
Attributes: std::ptr::null_mut(),
TargetAlias: windows::core::PWSTR::null(),
UserName: windows::core::PWSTR::null(),
};
let result = unsafe { CredWriteW(&credential, 0) };
let _ = (&mut target, &mut blob);
result.map_err(|e| Error::KeyOperation {
operation: "migrate_marker_set".into(),
detail: format!("CredWriteW: {e}"),
})
}
pub fn clear(app_name: &str) -> Result<()> {
let target = target_name_wide(app_name);
let result = unsafe { CredDeleteW(PCWSTR(target.as_ptr()), CRED_TYPE_GENERIC, 0) };
match result {
Ok(()) => Ok(()),
Err(e) if e.code() == ERROR_NOT_FOUND.to_hresult() => Ok(()),
Err(e) => Err(Error::KeyOperation {
operation: "migrate_marker_clear".into(),
detail: format!("CredDeleteW: {e}"),
}),
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::panic, let_underscore_drop)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
fn unique_app() -> String {
format!(
"enclaveapp-windows-migrate-marker-test-{}-{}",
std::process::id(),
COUNTER.fetch_add(1, Ordering::SeqCst),
)
}
#[test]
fn target_name_format() {
let wide = target_name_wide("sshenc");
assert_eq!(wide.last(), Some(&0));
let recovered = String::from_utf16(&wide[..wide.len() - 1]).unwrap();
assert_eq!(recovered, "com.godaddy.sshenc.migrate-marker");
let wide = target_name_wide("awsenc");
let recovered = String::from_utf16(&wide[..wide.len() - 1]).unwrap();
assert_eq!(recovered, "com.godaddy.awsenc.migrate-marker");
}
#[test]
#[ignore = "hits real Windows Credential Manager; run on the matrix or locally"]
fn set_clear_roundtrip() {
let app = unique_app();
clear(&app).expect("clear is idempotent");
assert!(matches!(is_set(&app), Ok(false)));
set(&app).expect("set succeeds");
assert!(matches!(is_set(&app), Ok(true)));
set(&app).expect("repeat set");
assert!(matches!(is_set(&app), Ok(true)));
clear(&app).expect("clear succeeds");
assert!(matches!(is_set(&app), Ok(false)));
}
}