1 /// Hardware identifiers (HWID) and processor features.
2 module tern.os.identifiers;
3 
4 import tern.string;
5 import tern.digest;
6 import tern.digest.sha;
7 version (Windows)
8 {
9     import std.windows.registry;
10 }
11 else version (linux)
12 {
13     import std.process;
14     import std.file;
15     import std.stdio : lines;
16 }
17 
18 public:
19 static:
20 // This implementation is not fast, but neither are most hwid extractions \_( -.-)_/
21 version (Windows)
22 {    
23     /// Retrieves the motherboard serial number. May fail and return null.
24     string moboSerial()
25     {
26         try
27         {
28             Key hKey = Registry.localMachine.getKey(r"SYSTEM\HardwareConfig");
29             return hKey.getValue("LastConfig").value_SZ.toLower()[1..$-1];
30         }
31         catch (RegistryException ex)
32         {
33             
34         }
35 
36         try
37         {
38             Key hKey = Registry.users.getKey(r".DEFAULT\Software\Microsoft\Office\Common\ClientTelemetry");
39             return hKey.getValue("MotherboardUUID").value_SZ.toLower()[1..$-1];
40         }
41         catch (RegistryException ex)
42         {
43             
44         }
45 
46         try
47         {
48             Key hKey = Registry.currentUser.getKey(r"Software\Microsoft\Office\Common\ClientTelemetry");
49             return hKey.getValue("MotherboardUUID").value_SZ.toLower()[1..$-1];
50         }
51         catch (RegistryException ex)
52         {
53             return null;
54         }
55     }
56 
57     /// Retrieves the monitor serial number. May fail and return null.
58     string monitorSerial()
59     {
60         try
61         {
62             Key hKey = Registry.localMachine.getKey(r"SYSTEM\CurrentControlSet\Enum\DISPLAY\");
63             hKey = hKey.keys[0];
64             hKey = hKey.keys[0];
65             hKey = hKey.keys[0];
66             return digest!SHA1(cast(ubyte[])hKey.getValue("EDID").value_BINARY).toHexString().toLower();
67         }
68         catch (RegistryException ex)
69         {
70             return null;
71         }
72     }
73 
74     /// Retrieves the disk serial number. May fail and return null.
75     string diskSerial()
76     {
77         try
78         {
79             Key hKey = Registry.localMachine.getKey(r"HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0");
80             return hKey.getValue("SerialNumber").value_SZ.toLower();
81         }
82         catch (RegistryException ex)
83         {
84 
85         }
86 
87         try
88         {
89             Key hKey = Registry.localMachine.getKey(r"HARDWARE\DESCRIPTION\System\MultifunctionAdapter\0\DiskController\0\DiskPeripheral");
90             hKey = hKey.keys[0];
91             return hKey.getValue("Identifier").value_SZ.toLower();
92         }
93         catch (RegistryException ex)
94         {
95             return null;
96         }
97     }
98 
99     /// Retrieves the sum SMBios serial number. May fail and return null.
100     string biosSerial()
101     {
102         try
103         {
104             Key hKey = Registry.localMachine.getKey(r"SYSTEM\CurrentControlSet\Services\mssmbios\Data");
105             byte[] table = hKey.getValue("AcpiData").value_BINARY~hKey.getValue("BiosData").value_BINARY~
106                 hKey.getValue("RegistersData").value_BINARY~hKey.getValue("SMBiosData").value_BINARY;
107             return digest!SHA1(cast(ubyte[])table).toHexString().toLower();
108         }
109         catch (RegistryException ex)
110         {
111             return null;
112         }
113     }
114 
115     /// Summation of all serials hashes into a single hardware id. Could be an invalid identifier but unlikely.
116     string hardwareId()
117     {
118         ubyte[] serials = cast(ubyte[])moboSerial()~cast(ubyte[])monitorSerial()~cast(ubyte[])diskSerial()~cast(ubyte[])biosSerial();
119         return digest!SHA1(serials).toHexString().toLower();
120     }
121 }
122 else version (linux)
123 {
124     /// Retrieves the motherboard serial number. Will never return null.
125     string moboSerial()
126     {
127         return readText(r"/sys/class/dmi/id/board_serial");
128     }
129 
130     /// Retrieves the chassis serial number. Will never return null.
131     string chassisSerial()
132     {
133         return readText(r"/sys/class/dmi/id/chassis_serial");
134     }
135 
136     /// Retrieves the disk serial number. May fail and return null.
137     string diskSerial()
138     {
139         auto process = pipeProcess("lsblk -no serial", Redirect.stdout);
140         wait(process.pid);
141         foreach (string line; lines(process.stdout))
142         {
143             if (!line.length) continue;
144             return line;
145         }
146         return null;
147     }
148 
149     /// Summation of all serials hashes into a single hardware id. Could be an invalid identifier but unlikely.
150     string hardwareId()
151     {
152         ubyte[] serials = cast(ubyte[])moboSerial()~cast(ubyte[])chassisSerial()~cast(ubyte[])diskSerial();
153         return digest!SHA1(serials).toHexString().toLower();
154     }
155 }