* Generates an enhanced CLI fingerprint using hardware identifiers. * This is deterministic - the same machine will always produce the same fingerprint. * Throws if machine ID cannot be obtained (to trigger legacy fallback).
()
| 82 | * Throws if machine ID cannot be obtained (to trigger legacy fallback). |
| 83 | */ |
| 84 | async function calculateEnhancedFingerprint(): Promise<string> { |
| 85 | // getMachineId will throw if it can't get a valid machine ID |
| 86 | const machineIdValue = await getMachineId() |
| 87 | |
| 88 | const [sysInfo, shell, networkInfo] = await Promise.all([ |
| 89 | getSystemInfo(), |
| 90 | Promise.resolve(detectShell()), |
| 91 | Promise.resolve(networkInterfaces()), |
| 92 | ]) |
| 93 | |
| 94 | // Extract MAC addresses for additional uniqueness |
| 95 | const macAddresses = Object.values(networkInfo) |
| 96 | .flat() |
| 97 | .filter( |
| 98 | (iface) => |
| 99 | iface && !iface.internal && iface.mac && iface.mac !== '00:00:00:00:00:00', |
| 100 | ) |
| 101 | .map((iface) => iface!.mac) |
| 102 | .sort() |
| 103 | |
| 104 | const fingerprintInfo = { |
| 105 | system: sysInfo.system, |
| 106 | cpu: sysInfo.cpu, |
| 107 | os: sysInfo.os, |
| 108 | runtime: { |
| 109 | nodeVersion: process.version, |
| 110 | platform: process.platform, |
| 111 | arch: process.arch, |
| 112 | shell, |
| 113 | cpuCount: cpus().length, |
| 114 | }, |
| 115 | network: { |
| 116 | macAddresses, |
| 117 | interfaceCount: Object.keys(networkInfo).length, |
| 118 | }, |
| 119 | machineId: machineIdValue, |
| 120 | fingerprintVersion: '2.0', |
| 121 | } |
| 122 | |
| 123 | const fingerprintString = JSON.stringify(fingerprintInfo) |
| 124 | const fingerprintHash = createHash('sha256') |
| 125 | .update(fingerprintString) |
| 126 | .digest('base64url') |
| 127 | |
| 128 | return `enhanced-${fingerprintHash}` |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Generates a legacy fingerprint with a random suffix. |
no test coverage detected