Files
volt/pkg/license/fingerprint.go
Karl Clinger 0ebe75b2ca Volt CLI: source-available under AGPSL v5.0
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
2026-03-21 02:08:15 -05:00

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")
}