1#![allow(non_snake_case)]
18
19mod errors;
20mod linux;
21mod macos;
22mod utils;
23mod windows;
24
25use errors::HWIDError;
26#[cfg(target_os = "linux")]
27use linux::{get_disk_id, get_hwid, get_mac_address};
28#[cfg(target_os = "macos")]
29use macos::{get_disk_id, get_hwid, get_mac_address};
30#[cfg(target_os = "windows")]
31use windows::{get_disk_id, get_hwid, get_mac_address};
32
33use hmac::{Hmac, Mac};
34use md5::{Digest as Md5Digest, Md5};
35#[allow(unused_imports)]
36use sha1::{Digest as Sha1Digest, Sha1};
37#[allow(unused_imports)]
38use sha2::{Digest as Sha256Digest, Sha256};
39use sysinfo::{CpuRefreshKind, RefreshKind, System};
40use utils::file_token;
41
42#[derive(Debug, PartialEq, Eq, Hash)]
45pub enum HWIDComponent {
46 SystemID,
48 CPUCores,
50 OSName,
52 Username,
54 MachineName,
56 MacAddress,
58 CPUID,
60 FileToken(&'static str),
62 DriveSerial,
64}
65
66impl HWIDComponent {
67 pub fn to_string(&self) -> Result<String, HWIDError> {
68 use HWIDComponent::*;
69
70 match self {
71 SystemID => get_hwid(),
72 CPUCores => {
73 let sys = System::new_with_specifics(
74 RefreshKind::nothing().with_cpu(CpuRefreshKind::nothing()),
75 );
76 let cores = sys
77 .physical_core_count()
78 .ok_or(HWIDError::new("CPUCores", "Could not retrieve CPU Cores"))?;
79 Ok(cores.to_string())
80 }
81 OSName => {
82 let name = System::long_os_version()
83 .ok_or(HWIDError::new("OSName", "Could not retrieve OS Name"))?;
84 Ok(name)
85 }
86 Username => Ok(whoami::username()),
87 MachineName => {
88 let name = System::host_name()
89 .ok_or(HWIDError::new("HostName", "Could not retrieve Host Name"))?;
90 Ok(name)
91 }
92 MacAddress => get_mac_address(),
93 CPUID => {
94 let sys = System::new_with_specifics(
95 RefreshKind::nothing().with_cpu(CpuRefreshKind::nothing()),
96 );
97 let processor = sys
98 .cpus()
99 .first()
100 .ok_or(HWIDError::new("CPUID", "Could not retrieve CPU ID"))?;
101 Ok(processor.vendor_id().to_string())
102 }
103 FileToken(filename) => file_token(filename),
104 DriveSerial => get_disk_id(),
105 }
106 }
107}
108
109pub enum Encryption {
111 MD5,
112 SHA256,
113 SHA1,
114}
115
116type HmacMd5 = Hmac<Md5>;
117type HmacSha1 = Hmac<Sha1>;
118type HmacSha256 = Hmac<Sha256>;
119
120impl Encryption {
121 fn generate_hash(&self, key: Option<&[u8]>, text: String) -> Result<String, HWIDError> {
122 match self {
123 Encryption::MD5 => {
124 if key.is_none() {
125 let mut hasher = Md5::new();
126 hasher.update(text.as_bytes());
127 Ok(hex::encode(hasher.finalize()))
128 } else {
129 let mut mac = HmacMd5::new_from_slice(key.unwrap())?;
130 mac.update(text.as_bytes());
131 let result = mac.finalize();
132 Ok(hex::encode(result.into_bytes().as_slice()))
133 }
134 }
135 Encryption::SHA1 => {
136 if key.is_none() {
137 let mut hasher = Sha1::new();
138 hasher.update(text.as_bytes());
139 Ok(hex::encode(hasher.finalize()))
140 } else {
141 let mut mac = HmacSha1::new_from_slice(key.unwrap())?;
142 mac.update(text.as_bytes());
143 let result = mac.finalize();
144 Ok(hex::encode(result.into_bytes().as_slice()))
145 }
146 }
147 Encryption::SHA256 => {
148 if key.is_none() {
149 let mut hasher = Sha256::new();
150 hasher.update(text.as_bytes());
151 Ok(hex::encode(hasher.finalize()))
152 } else {
153 let mut mac = HmacSha256::new_from_slice(key.unwrap())?;
154 mac.update(text.as_bytes());
155 let result = mac.finalize();
156 Ok(hex::encode(result.into_bytes().as_slice()))
157 }
158 }
159 }
160 }
161}
162
163pub struct IdBuilder {
165 parts: Vec<HWIDComponent>,
166 pub hash: Encryption,
167}
168
169impl IdBuilder {
170 pub fn build(&mut self, key: Option<&str>) -> Result<String, HWIDError> {
190 if self.parts.is_empty() {
191 panic!("You must add at least one element to make a machine id");
192 }
193 let final_string = self
194 .parts
195 .iter()
196 .map(|p| p.to_string())
197 .collect::<Result<String, HWIDError>>()?;
198
199 self.hash
200 .generate_hash(key.map(|k| k.as_bytes()), final_string)
201 }
202
203 pub fn add_component(&mut self, component: HWIDComponent) -> &mut Self {
217 if !self.parts.contains(&component) {
218 self.parts.push(component);
219 }
220 self
221 }
222
223 pub fn add_all(&mut self) -> &mut Self {
254 self.add_component(HWIDComponent::SystemID)
255 .add_component(HWIDComponent::OSName)
256 .add_component(HWIDComponent::CPUCores)
257 .add_component(HWIDComponent::CPUID)
258 .add_component(HWIDComponent::DriveSerial)
259 .add_component(HWIDComponent::MacAddress)
260 .add_component(HWIDComponent::Username)
261 .add_component(HWIDComponent::MachineName)
262 }
263
264 pub fn new(hash: Encryption) -> Self {
274 IdBuilder {
275 parts: vec![],
276 hash,
277 }
278 }
279}
280
281#[cfg(test)]
282mod test {
283 use super::*;
284 use std::env;
285
286 #[test]
287 fn every_option_sha256() {
288 let mut builder = IdBuilder::new(Encryption::SHA256);
289 builder
290 .add_component(HWIDComponent::SystemID)
291 .add_component(HWIDComponent::OSName)
292 .add_component(HWIDComponent::CPUCores)
293 .add_component(HWIDComponent::CPUID)
294 .add_component(HWIDComponent::DriveSerial)
295 .add_component(HWIDComponent::MacAddress)
296 .add_component(HWIDComponent::FileToken("test.txt"))
297 .add_component(HWIDComponent::Username)
298 .add_component(HWIDComponent::MachineName);
299 let hash = builder.build(None).unwrap();
300 if let Ok(expected) = env::var("SHA256_MACHINEID_HASH") {
301 assert_eq!(expected, hash);
302 }
303 }
304
305 #[test]
306 fn every_option_sha1() {
307 let mut builder = IdBuilder::new(Encryption::SHA1);
308 builder
309 .add_component(HWIDComponent::SystemID)
310 .add_component(HWIDComponent::OSName)
311 .add_component(HWIDComponent::CPUCores)
312 .add_component(HWIDComponent::CPUID)
313 .add_component(HWIDComponent::DriveSerial)
314 .add_component(HWIDComponent::MacAddress)
315 .add_component(HWIDComponent::FileToken("test.txt"))
316 .add_component(HWIDComponent::Username)
317 .add_component(HWIDComponent::MachineName);
318 let hash = builder.build(None).unwrap();
319 if let Ok(expected) = env::var("SHA1_MACHINEID_HASH") {
320 assert_eq!(expected, hash);
321 }
322 }
323
324 #[test]
325 fn every_option_md5() {
326 let mut builder = IdBuilder::new(Encryption::MD5);
327 builder
328 .add_component(HWIDComponent::SystemID)
329 .add_component(HWIDComponent::OSName)
330 .add_component(HWIDComponent::CPUCores)
331 .add_component(HWIDComponent::CPUID)
332 .add_component(HWIDComponent::DriveSerial)
333 .add_component(HWIDComponent::MacAddress)
334 .add_component(HWIDComponent::FileToken("test.txt"))
335 .add_component(HWIDComponent::Username)
336 .add_component(HWIDComponent::MachineName);
337 let hash = builder.build(None).unwrap();
338 if let Ok(expected) = env::var("MD5_MACHINEID_HASH") {
339 assert_eq!(expected, hash);
340 }
341 }
342
343 #[test]
344 fn every_option_sha256_hmac() {
345 let mut builder = IdBuilder::new(Encryption::SHA256);
346 builder
347 .add_component(HWIDComponent::SystemID)
348 .add_component(HWIDComponent::OSName)
349 .add_component(HWIDComponent::CPUCores)
350 .add_component(HWIDComponent::CPUID)
351 .add_component(HWIDComponent::DriveSerial)
352 .add_component(HWIDComponent::MacAddress)
353 .add_component(HWIDComponent::FileToken("test.txt"))
354 .add_component(HWIDComponent::Username)
355 .add_component(HWIDComponent::MachineName);
356 let hash = builder.build(Some("mykey")).unwrap();
357 if let Ok(expected) = env::var("SHA256_MACHINEID_HASH") {
358 assert_eq!(expected, hash);
359 }
360 }
361
362 #[test]
363 fn every_option_sha1_hmac() {
364 let mut builder = IdBuilder::new(Encryption::SHA1);
365 builder
366 .add_component(HWIDComponent::SystemID)
367 .add_component(HWIDComponent::OSName)
368 .add_component(HWIDComponent::CPUCores)
369 .add_component(HWIDComponent::CPUID)
370 .add_component(HWIDComponent::DriveSerial)
371 .add_component(HWIDComponent::MacAddress)
372 .add_component(HWIDComponent::FileToken("test.txt"))
373 .add_component(HWIDComponent::Username)
374 .add_component(HWIDComponent::MachineName);
375 let hash = builder.build(Some("mykey")).unwrap();
376 if let Ok(expected) = env::var("SHA1_MACHINEID_HASH") {
377 assert_eq!(expected, hash);
378 }
379 }
380
381 #[test]
382 fn every_option_md5_hmac() {
383 let mut builder = IdBuilder::new(Encryption::MD5);
384 builder
385 .add_component(HWIDComponent::SystemID)
386 .add_component(HWIDComponent::OSName)
387 .add_component(HWIDComponent::CPUCores)
388 .add_component(HWIDComponent::CPUID)
389 .add_component(HWIDComponent::DriveSerial)
390 .add_component(HWIDComponent::MacAddress)
391 .add_component(HWIDComponent::Username)
393 .add_component(HWIDComponent::MachineName);
394 let hash = builder.build(Some("mykey")).unwrap();
395 if let Ok(expected) = env::var("MD5_MACHINEID_HASH") {
396 assert_eq!(expected, hash);
397 }
398 }
399}