1#![allow(non_snake_case)]
18
19mod errors;
20mod linux;
21mod utils;
22mod windows;
23mod macos;
24
25use errors::HWIDError;
26#[cfg(target_os = "linux")]
27use linux::{get_disk_id, get_hwid, get_mac_address};
28#[cfg(target_os = "windows")]
29use windows::{get_disk_id, get_hwid, get_mac_address};
30#[cfg(target_os = "macos")]
31use macos::{get_disk_id, get_hwid, get_mac_address};
32
33use hmac::{Hmac, Mac};
34use md5::Md5;
35use sha1::Sha1;
36use sha2::Sha256;
37use sysinfo::{CpuExt, System, SystemExt};
38use utils::file_token;
39
40#[derive(PartialEq, Eq, Hash)]
43pub enum HWIDComponent {
44 SystemID,
46 CPUCores,
48 OSName,
50 Username,
52 MachineName,
54 MacAddress,
56 CPUID,
58 FileToken(&'static str),
60 DriveSerial,
62}
63
64impl HWIDComponent {
65 fn to_string(&self) -> Result<String, HWIDError> {
66 use HWIDComponent::*;
67 return match self {
68 SystemID => get_hwid(),
69 CPUCores => {
70 let sys = System::new_all();
71 let cores = sys.physical_core_count().unwrap_or(2);
72 Ok(cores.to_string())
73 }
74 OSName => {
75 let sys = System::new_all();
76 let name = sys
77 .long_os_version()
78 .ok_or(HWIDError::new("OSName", "Could not retrieve OS Name"))?;
79 Ok(name)
80 }
81 Username => Ok(whoami::username()),
82 MachineName => {
83 let sys = System::new_all();
84 let name = sys
85 .host_name()
86 .ok_or(HWIDError::new("HostName", "Could not retrieve Host Name"))?;
87 Ok(name)
88 }
89 MacAddress => get_mac_address(),
90 CPUID => {
91 let sys = System::new_all();
92 let processor = sys.global_cpu_info();
93 Ok(processor.vendor_id().to_string())
94 }
95 FileToken(filename) => file_token(filename),
96 DriveSerial => get_disk_id(),
97 };
98 }
99}
100
101pub enum Encryption {
103 MD5,
104 SHA256,
105 SHA1,
106}
107
108type HmacMd5 = Hmac<Md5>;
109type HmacSha1 = Hmac<Sha1>;
110type HmacSha256 = Hmac<Sha256>;
111
112impl Encryption {
113 fn generate_hash(&self, key: &[u8], text: String) -> Result<String, HWIDError> {
114 match self {
115 Encryption::MD5 => {
116 let mut mac = HmacMd5::new_from_slice(key)?;
117 mac.update(text.as_bytes());
118 let result = mac.finalize();
119 Ok(hex::encode(result.into_bytes().as_slice()))
120 }
121 Encryption::SHA1 => {
122 let mut mac = HmacSha1::new_from_slice(key)?;
123 mac.update(text.as_bytes());
124 let result = mac.finalize();
125 Ok(hex::encode(result.into_bytes().as_slice()))
126 }
127 Encryption::SHA256 => {
128 let mut mac = HmacSha256::new_from_slice(key)?;
129 mac.update(text.as_bytes());
130 let result = mac.finalize();
131 Ok(hex::encode(result.into_bytes().as_slice()))
132 }
133 }
134 }
135}
136
137pub struct IdBuilder {
139 parts: Vec<HWIDComponent>,
140 pub hash: Encryption,
141}
142
143impl IdBuilder {
144 pub fn build(&mut self, key: &str) -> Result<String, HWIDError> {
164 if self.parts.len() == 0 {
165 panic!("You must add at least one element to make a machine id");
166 }
167 let final_string = self
168 .parts
169 .iter()
170 .map(|p| p.to_string())
171 .collect::<Result<String, HWIDError>>()?;
172 self.hash.generate_hash(key.as_bytes(), final_string)
173 }
174
175 pub fn add_component(&mut self, component: HWIDComponent) -> &mut Self {
189 if !self.parts.contains(&component) {
190 self.parts.push(component);
191 }
192 return self;
193 }
194
195 pub fn new(hash: Encryption) -> Self {
205 IdBuilder {
206 parts: vec![],
207 hash,
208 }
209 }
210}
211
212#[cfg(test)]
213mod test {
214 use super::*;
215 use std::env;
216 #[test]
217 fn every_option_sha256() {
218 let mut builder = IdBuilder::new(Encryption::SHA256);
219 builder
220 .add_component(HWIDComponent::SystemID)
221 .add_component(HWIDComponent::OSName)
222 .add_component(HWIDComponent::CPUCores)
223 .add_component(HWIDComponent::CPUID)
224 .add_component(HWIDComponent::DriveSerial)
225 .add_component(HWIDComponent::MacAddress)
226 .add_component(HWIDComponent::FileToken("test.txt"))
227 .add_component(HWIDComponent::Username)
228 .add_component(HWIDComponent::MachineName);
229 let hash = builder.build("mykey").unwrap();
230 let expected = env::var("SHA256_MACHINEID_HASH").unwrap();
231 assert_eq!(expected, hash);
232 }
233
234 #[test]
235 fn every_option_sha1() {
236 let mut builder = IdBuilder::new(Encryption::SHA1);
237 builder
238 .add_component(HWIDComponent::SystemID)
239 .add_component(HWIDComponent::OSName)
240 .add_component(HWIDComponent::CPUCores)
241 .add_component(HWIDComponent::CPUID)
242 .add_component(HWIDComponent::DriveSerial)
243 .add_component(HWIDComponent::MacAddress)
244 .add_component(HWIDComponent::FileToken("test.txt"))
245 .add_component(HWIDComponent::Username)
246 .add_component(HWIDComponent::MachineName);
247 let hash = builder.build("mykey").unwrap();
248 let expected = env::var("SHA1_MACHINEID_HASH").unwrap();
249 assert_eq!(expected, hash);
250 }
251
252 #[test]
253 fn every_option_md5() {
254 let mut builder = IdBuilder::new(Encryption::MD5);
255 builder
256 .add_component(HWIDComponent::SystemID)
257 .add_component(HWIDComponent::OSName)
258 .add_component(HWIDComponent::CPUCores)
259 .add_component(HWIDComponent::CPUID)
260 .add_component(HWIDComponent::DriveSerial)
261 .add_component(HWIDComponent::MacAddress)
262 .add_component(HWIDComponent::FileToken("test.txt"))
263 .add_component(HWIDComponent::Username)
264 .add_component(HWIDComponent::MachineName);
265 let hash = builder.build("mykey").unwrap();
266 let expected = env::var("MD5_MACHINEID_HASH").unwrap();
267 assert_eq!(expected, hash);
268 }
269}