use crate::error::Error;
use crate::source::{Probe, Source, SourceKind};
use crate::sources::util::normalize;
const KEY_PATH: &str = r"SOFTWARE\Microsoft\Cryptography";
const FULL_KEY: &str = r"HKLM\SOFTWARE\Microsoft\Cryptography";
const VALUE_NAME: &str = "MachineGuid";
#[derive(Debug, Default, Clone)]
pub struct WindowsMachineGuid {
_priv: (),
}
impl WindowsMachineGuid {
#[must_use]
pub fn new() -> Self {
Self { _priv: () }
}
}
impl Source for WindowsMachineGuid {
fn kind(&self) -> SourceKind {
SourceKind::WindowsMachineGuid
}
fn probe(&self) -> Result<Option<Probe>, Error> {
let key = match windows_registry::LOCAL_MACHINE.open(KEY_PATH) {
Ok(key) => key,
Err(err) if is_benign_registry_error(&err) => {
log::debug!("host-identity: windows-machine-guid: open {FULL_KEY}: {err}");
return Ok(None);
}
Err(err) => {
return Err(Error::Platform {
source_kind: SourceKind::WindowsMachineGuid,
reason: format!("open {FULL_KEY}: {err}"),
});
}
};
let value = match key.get_string(VALUE_NAME) {
Ok(v) => v,
Err(err) if is_benign_registry_error(&err) => {
log::debug!("host-identity: windows-machine-guid: read {VALUE_NAME}: {err}");
return Ok(None);
}
Err(err) => {
return Err(Error::Platform {
source_kind: SourceKind::WindowsMachineGuid,
reason: format!("read {VALUE_NAME}: {err}"),
});
}
};
Ok(probe_from_registry_value(&value))
}
}
fn is_benign_registry_error(err: &windows_result::Error) -> bool {
let code = err.code().0 as u32 & 0xFFFF;
code == 2 || code == 5
}
fn probe_from_registry_value(value: &str) -> Option<Probe> {
normalize(value).map(|v| Probe::new(SourceKind::WindowsMachineGuid, v))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sentinel_registry_value_yields_none() {
assert!(probe_from_registry_value("uninitialized").is_none());
assert!(probe_from_registry_value("UNINITIALIZED\r\n").is_none());
}
#[test]
fn empty_registry_value_yields_none() {
assert!(probe_from_registry_value("").is_none());
assert!(probe_from_registry_value(" ").is_none());
}
#[test]
fn usable_registry_value_yields_probe() {
let probe = probe_from_registry_value("12345678-1234-1234-1234-123456789ABC")
.expect("usable value should yield a probe");
assert_eq!(probe.kind(), SourceKind::WindowsMachineGuid);
assert_eq!(probe.value(), "12345678-1234-1234-1234-123456789ABC");
}
}