Complete infrastructure platform CLI: - Container runtime (systemd-nspawn) - VoltVisor VMs (Neutron Stardust / QEMU) - Stellarium CAS (content-addressed storage) - ORAS Registry - GitOps integration - Landlock LSM security - Compose orchestration - Mesh networking Copyright (c) Armored Gates LLC. All rights reserved. Licensed under AGPSL v5.0
96 lines
2.1 KiB
Go
96 lines
2.1 KiB
Go
/*
|
|
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")
|
|
}
|