├── .github └── workflows │ └── test.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── get_hwid.rs └── src └── lib.rs /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | system: [ubuntu-latest, macos-latest, windows-latest] 10 | runs-on: ${{ matrix.system }} 11 | if: "!contains(github.event.head_commit.message, '[skip]')" 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Build 15 | run: | 16 | cargo build --verbose 17 | - name: Test 18 | run: | 19 | cargo run --example get_hwid 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hardware-id" 3 | version = "0.3.0" 4 | description = "Access Hardware ID information on Windows, macOS and Linux platforms" 5 | repository = "https://github.com/tilda/rust-hwid" 6 | keywords = ["windows", "macos", "linux"] 7 | categories = ["os"] 8 | authors = ["tilda "] 9 | edition = "2021" 10 | license = "MIT" 11 | 12 | # https://stackoverflow.com/a/51821632/364875 13 | [target.'cfg(target_os = "windows")'.dependencies] 14 | winreg = "0.10.1" 15 | 16 | [dependencies] 17 | thiserror = "1.0.31" 18 | 19 | [[example]] 20 | name = "get_hwid" 21 | crate-type = ["bin"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 tilda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-hwid 2 | 3 | A simple library to detect an OS equivalent of an Hardware ID 4 | 5 | # Currently supported 6 | - Windows 7 | - macOS 8 | - Linux (dbus, systemd HWIDs) 9 | 10 | # TODO 11 | Find a way to support *BSDs or ditch the function for them entirely 12 | 13 | # Usage 14 | There is a single function: `get_id()` 15 | 16 | An example is provided in the `examples` folder. -------------------------------------------------------------------------------- /examples/get_hwid.rs: -------------------------------------------------------------------------------- 1 | extern crate hardware_id; 2 | 3 | use hardware_id::get_id; 4 | 5 | fn main() { 6 | let hwid = get_id().unwrap(); 7 | println!("{}", hwid); 8 | } 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // rust-hwid 2 | // (c) 2020 tilda, under MIT license 3 | 4 | //! Get a "Hardware ID" for the host machine. This is a UUID 5 | //! which is intended to uniquely represent this entity. 6 | 7 | use thiserror::Error; 8 | 9 | /// Possible failure cases for [get_id()]. 10 | #[derive(Debug, Error)] 11 | pub enum HwIdError { 12 | /// Could not detect a hardware id. This might be caused 13 | /// by a misconfigured system or by this feature not 14 | /// being supported by the system or platform. 15 | #[error("no HWID was found on system")] 16 | NotFound, 17 | /// Found a putative HWID, but something was wrong with 18 | /// it. The `String` argument contains a path or other 19 | /// identifier at which the HWID was found. This will 20 | /// usually indicate something is really wrong with the 21 | /// system. 22 | #[error("{0:?}: contains malformed HWID")] 23 | Malformed(String), 24 | } 25 | 26 | #[cfg(target_os = "windows")] 27 | mod hwid { 28 | use super::*; 29 | use winreg::enums::{HKEY_LOCAL_MACHINE, KEY_QUERY_VALUE}; 30 | 31 | /// Get the hardware ID of this machine. The HWID is 32 | /// obtained from the Windows registry at location 33 | /// `\\\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid`. 34 | pub fn get_id() -> Result { 35 | // escaping is fun, right? right??? 36 | let hive = winreg::RegKey::predef(HKEY_LOCAL_MACHINE) 37 | .open_subkey_with_flags("Software\\Microsoft\\Cryptography", KEY_QUERY_VALUE) 38 | .or(Err(HwIdError::NotFound))?; 39 | let id = hive.get_value("MachineGuid").or(Err(HwIdError::NotFound))?; 40 | Ok(id) 41 | } 42 | } 43 | 44 | #[cfg(target_os = "macos")] 45 | mod hwid { 46 | use super::*; 47 | 48 | /// Get the hardware ID of this machine. The HWID is 49 | /// obtained by running 50 | /// 51 | /// ```text 52 | /// ioreg -rd1 -c IOExpertPlatformDevice 53 | /// ``` 54 | /// 55 | /// and returning the result. 56 | pub fn get_id() -> Result { 57 | let cmd = std::process::Command::new("ioreg") 58 | .arg("-rd1") 59 | .arg("-c") 60 | .arg("IOPlatformExpertDevice") 61 | .output() 62 | .or(Err(HwIdError::NotFound))? 63 | .stdout; 64 | let out = String::from_utf8(cmd).or(Err(HwIdError::Malformed(String::from("ioreg"))))?; 65 | match out 66 | .lines() 67 | .find(|l| l.contains("IOPlatformUUID")) 68 | .unwrap_or("") 69 | .split('=') 70 | .nth(1) 71 | .unwrap_or("") 72 | .split('\"') 73 | .nth(1) 74 | { 75 | None => Err(HwIdError::NotFound), 76 | Some(id) => { 77 | if id.is_empty() { 78 | Err(HwIdError::Malformed(String::from("ioreg"))) 79 | } else { 80 | Ok(id.to_string()) 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | #[cfg(target_os = "linux")] 88 | mod hwid { 89 | use super::*; 90 | 91 | /// Get the hardware ID of this machine. The HWID is 92 | /// obtained from `/var/lib/dbus/machine-id`, or failing 93 | /// that from `/etc/machine-id`. 94 | pub fn get_id() -> Result { 95 | let paths = ["/var/lib/dbus/machine-id", "/etc/machine-id"]; 96 | for p in paths { 97 | if let Ok(id_contents) = std::fs::read_to_string(p) { 98 | let id_str = id_contents 99 | .lines() 100 | .next() 101 | .ok_or_else(|| HwIdError::Malformed(id_contents.to_string()))?; 102 | return Ok(id_str.to_string()); 103 | } 104 | } 105 | Err(HwIdError::NotFound) 106 | } 107 | } 108 | 109 | #[cfg(target_os = "freebsd")] 110 | #[cfg(target_os = "dragonfly")] 111 | #[cfg(target_os = "openbsd")] 112 | #[cfg(target_os = "netbsd")] 113 | mod hwid { 114 | pub fn get_id() -> std::string::String { 115 | unimplemented!("*BSD support is not implemented") 116 | } 117 | } 118 | 119 | pub use crate::hwid::get_id; 120 | --------------------------------------------------------------------------------