/* Volt Platform — Machine Fingerprint Generation Creates a unique, deterministic identifier for the current node */ package license import ( "bufio" "crypto/sha256" "fmt" "os" "strings" ) // GenerateFingerprint creates a machine fingerprint by hashing: // - /etc/machine-id // - CPU model from /proc/cpuinfo // - Total memory from /proc/meminfo // Returns a 32-character hex-encoded string func GenerateFingerprint() (string, error) { machineID, err := readMachineID() if err != nil { return "", fmt.Errorf("failed to read machine-id: %w", err) } cpuModel, err := readCPUModel() if err != nil { // CPU model is best-effort cpuModel = "unknown" } totalMem, err := readTotalMemory() if err != nil { // Memory is best-effort totalMem = "unknown" } // Combine and hash data := fmt.Sprintf("volt-fp:%s:%s:%s", machineID, cpuModel, totalMem) hash := sha256.Sum256([]byte(data)) // Return first 32 hex chars (16 bytes) return fmt.Sprintf("%x", hash[:16]), nil } // readMachineID reads /etc/machine-id func readMachineID() (string, error) { data, err := os.ReadFile("/etc/machine-id") if err != nil { return "", err } return strings.TrimSpace(string(data)), nil } // readCPUModel reads the CPU model from /proc/cpuinfo func readCPUModel() (string, error) { f, err := os.Open("/proc/cpuinfo") if err != nil { return "", err } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "model name") { parts := strings.SplitN(line, ":", 2) if len(parts) == 2 { return strings.TrimSpace(parts[1]), nil } } } return "", fmt.Errorf("model name not found in /proc/cpuinfo") } // readTotalMemory reads total memory from /proc/meminfo func readTotalMemory() (string, error) { f, err := os.Open("/proc/meminfo") if err != nil { return "", err } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "MemTotal:") { fields := strings.Fields(line) if len(fields) >= 2 { return fields[1], nil } } } return "", fmt.Errorf("MemTotal not found in /proc/meminfo") }