xmid/lib.rs
1//! Creating a Machine ID hash for MacOS/Windows/Linux.
2//!
3//! ```
4//! let machine_id = mid::get("mySecretKey").unwrap();
5//! ```
6
7mod errors;
8mod linux;
9mod macos;
10mod utils;
11mod windows;
12
13use errors::MIDError;
14use hmac_sha256::HMAC;
15
16#[cfg(target_os = "linux")]
17use linux::get_mid_result;
18#[cfg(target_os = "macos")]
19use macos::get_additional_data;
20#[cfg(target_os = "macos")]
21use macos::get_mid_result;
22#[cfg(target_os = "windows")]
23use windows::get_mid_result;
24
25#[derive(Debug)]
26pub struct MidData {
27 pub key: String,
28 pub result: Vec<String>,
29 pub hash: String,
30}
31
32#[derive(Debug)]
33#[cfg(target_os = "macos")]
34pub struct AdditionalData {
35 pub username: String,
36 pub hostname: String,
37 pub os_name: String,
38 pub os_version: String,
39 pub os_full: String,
40 pub chip: String,
41 pub memsize: u8,
42 pub cpu_core_count: u8,
43 pub languages: Vec<String>,
44}
45
46/// Gets unique platform metrics and returns a `Result`, which can be a MID hash (SHA-256) or a `MIDError`.
47///
48/// # Errors
49///
50/// Returns [`Err`] if an error occurred while creating the MachineID.
51///
52/// # Example
53///
54/// ```
55/// fn get_machine_id() -> Result<String, String> {
56/// match mid::get("mySecretKey") {
57/// Ok(mid) => Ok(mid),
58/// Err(err) => {
59/// println!("MID error: {}", err.to_string());
60/// Err(err.to_string())
61/// }
62/// }
63/// }
64/// ```
65pub fn get(key: &str) -> Result<String, MIDError> {
66 match data(key) {
67 Ok(mid) => Ok(mid.hash),
68 Err(err) => Err(err),
69 }
70}
71
72/// Returns MID key/result/hash as [`MidData`]
73///
74/// # Errors
75///
76/// Returns [`Err`] if an error occurred while creating the MachineID.
77///
78/// # Example
79///
80/// ```
81/// let mid_data = mid::data("mySecretKey").unwrap();
82/// ```
83pub fn data(key: &str) -> Result<MidData, MIDError> {
84 if key.is_empty() {
85 return Err(MIDError::EmptyMidKey);
86 }
87
88 match get_mid_result() {
89 Ok(mid) => {
90 let mid_result: Vec<String> = mid.split('|').map(|s| s.to_string()).collect();
91
92 let hmac_result = HMAC::mac(mid.as_bytes(), key.as_bytes());
93 let mid_hash = hex::encode(hmac_result);
94
95 Ok(MidData {
96 key: String::from(key),
97 result: mid_result,
98 hash: mid_hash,
99 })
100 }
101 Err(err) => Err(err),
102 }
103}
104
105/// Returns additional device data that is not involved in generating the device hash as [`AdditionalData`]
106///
107/// # Errors
108///
109/// Returns [`Err`] if an error occurred while retrieving additional data.
110///
111/// # Example
112///
113/// ```
114/// let additional_data = mid::additional_data().unwrap();
115/// println!("Username: {}", additional_data.username);
116/// println!("Hostname: {}", additional_data.hostname);
117/// println!("OS Name: {}", additional_data.os_name);
118/// println!("OS Version: {}", additional_data.os_version);
119/// println!("OS Full: {}", additional_data.os_full);
120/// println!("Chip: {}", additional_data.chip);
121/// println!("Memory Size: {}", additional_data.memsize);
122/// println!("CPU Core Count: {}", additional_data.cpu_core_count);
123/// println!("Languages: {:?}", additional_data.languages);
124/// ```
125#[cfg(target_os = "macos")]
126pub fn additional_data() -> Result<AdditionalData, MIDError> {
127 match get_additional_data() {
128 Ok(additional_data) => Ok(additional_data),
129 Err(err) => Err(err),
130 }
131}
132
133/// Output the MID key/result/hash to the console in `debug_assertions` mode.
134///
135/// `MID key` - The secret key for hashing
136///
137/// `MID result` - Array of OS parameters
138///
139/// `MID hash` - SHA-256 hash from result
140///
141/// # Example
142///
143/// ```
144/// mid::print("mySecretKey");
145/// ```
146pub fn print(key: &str) {
147 match data(key) {
148 Ok(mid) => {
149 debug!("MID.print[key]: {}", mid.key);
150 debug!("MID.print[result]: {:?}", mid.result);
151 debug!("MID.print[hash]: {}", mid.hash);
152 }
153 Err(err) => debug!("MID.print[error]: {}", err),
154 }
155}
156
157#[test]
158fn test_mid_operations() {
159 match get("mykey") {
160 Ok(mid) => debug!("MID.get: {}", mid),
161 Err(err) => debug!("MID.get[error]: {}", err),
162 }
163
164 match data("mykey") {
165 Ok(log_data) => debug!("MID.data: {:?}", log_data),
166 Err(err) => debug!("MID.data[error]: {}", err),
167 }
168
169 #[cfg(target_os = "macos")]
170 match additional_data() {
171 Ok(log_data) => debug!("MID.additional_data: {:?}", log_data),
172 Err(err) => debug!("MID.additional_data[error]: {}", err),
173 }
174
175 print("mykey");
176}