v1.0.0
This commit is contained in:
171
backend/utils/machine-identifier.go
Normal file
171
backend/utils/machine-identifier.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/jaypipes/ghw"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
type MachineInfo struct {
|
||||
Hostname string `json:"Hostname"`
|
||||
OS string `json:"OS"`
|
||||
Version string `json:"Version"`
|
||||
HWID string `json:"HWID"`
|
||||
ExternalIP string `json:"ExternalIP"`
|
||||
CPU ghw.CPUInfo `json:"CPU"`
|
||||
RAM ghw.MemoryInfo `json:"RAM"`
|
||||
GPU ghw.GPUInfo `json:"GPU"`
|
||||
}
|
||||
|
||||
func GetMachineInfo() (*MachineInfo, error) {
|
||||
info := &MachineInfo{}
|
||||
|
||||
// 1. Get Hostname
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get hostname: %w", err)
|
||||
}
|
||||
info.Hostname = hostname
|
||||
|
||||
// 2. Get OS Info
|
||||
info.OS = fmt.Sprintf("%s %s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
// 3. Get Version Info
|
||||
k, _ := registry.OpenKey(
|
||||
registry.LOCAL_MACHINE,
|
||||
`SOFTWARE\Microsoft\Windows NT\CurrentVersion`,
|
||||
registry.QUERY_VALUE,
|
||||
)
|
||||
defer k.Close()
|
||||
|
||||
product, _, _ := k.GetStringValue("ProductName")
|
||||
build, _, _ := k.GetStringValue("CurrentBuild")
|
||||
ubr, _, _ := k.GetIntegerValue("UBR")
|
||||
display, _, _ := k.GetStringValue("DisplayVersion")
|
||||
edition, _, _ := k.GetStringValue("EditionID")
|
||||
|
||||
// Append edition if available
|
||||
if edition != "" {
|
||||
product = fmt.Sprintf("%s %s", product, edition)
|
||||
}
|
||||
|
||||
// Split display versione via H (like 23H2, 24H2, 25H2), if its => 23, then its Windows 11, not 10
|
||||
if strings.HasPrefix(display, "2") {
|
||||
parts := strings.SplitN(display, "H", 2)
|
||||
if len(parts) > 0 {
|
||||
yearPart := parts[0]
|
||||
if yearPartInt := strings.TrimSpace(yearPart); yearPartInt >= "23" {
|
||||
product = "Windows 11"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.Version = fmt.Sprintf("%s %s %s (Build %s.%d)", product, display, edition, build, ubr)
|
||||
|
||||
// 3. Get HWID (Windows specific via wmic)
|
||||
// Fallback or different implementation needed for Linux/Mac if required
|
||||
if runtime.GOOS == "windows" {
|
||||
out, err := exec.Command("wmic", "csproduct", "get", "uuid").Output()
|
||||
if err == nil {
|
||||
// Parse output which looks like "UUID \n <UUID> \n\n"
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed != "" && trimmed != "UUID" {
|
||||
info.HWID = trimmed
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to registry MachineGuid if wmic fails or empty
|
||||
if info.HWID == "" {
|
||||
// Simplified registry read attempt using reg query command to avoid cgo/syscall complexity for now
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography -> MachineGuid
|
||||
out, err := exec.Command("reg", "query", `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography`, "/v", "MachineGuid").Output()
|
||||
if err == nil {
|
||||
// Parse output
|
||||
content := string(out)
|
||||
if idx := strings.Index(content, "REG_SZ"); idx != -1 {
|
||||
info.HWID = strings.TrimSpace(content[idx+6:])
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info.HWID = "Not implemented for " + runtime.GOOS
|
||||
}
|
||||
|
||||
// 4. Get External IP
|
||||
ip, err := getExternalIP()
|
||||
if err == nil {
|
||||
info.ExternalIP = ip
|
||||
} else {
|
||||
info.ExternalIP = "Unavailable"
|
||||
}
|
||||
|
||||
// 5. Get CPU Info
|
||||
cpuInfo, err := getCPUInfo()
|
||||
if err == nil {
|
||||
info.CPU = *cpuInfo
|
||||
}
|
||||
|
||||
// 6. Get GPU Info
|
||||
gpuInfo, err := getGPUInfo()
|
||||
if err == nil {
|
||||
info.GPU = *gpuInfo
|
||||
}
|
||||
|
||||
// 7. Get RAM Info
|
||||
ramInfo, err := getRAMInfo()
|
||||
if err == nil {
|
||||
info.RAM = *ramInfo
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func getExternalIP() (string, error) {
|
||||
resp, err := http.Get("https://api.ipify.org?format=text")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
func getCPUInfo() (*ghw.CPUInfo, error) {
|
||||
cpuInfo, _ := ghw.CPU()
|
||||
if cpuInfo == nil {
|
||||
return nil, fmt.Errorf("failed to get CPU info")
|
||||
}
|
||||
return cpuInfo, nil
|
||||
}
|
||||
|
||||
func getGPUInfo() (*ghw.GPUInfo, error) {
|
||||
gpuInfo, err := ghw.GPU()
|
||||
if gpuInfo == nil {
|
||||
return nil, fmt.Errorf("failed to get GPU info: %w", err)
|
||||
}
|
||||
return gpuInfo, nil
|
||||
}
|
||||
|
||||
func getRAMInfo() (*ghw.MemoryInfo, error) {
|
||||
memory, err := ghw.Memory()
|
||||
if memory == nil {
|
||||
return nil, fmt.Errorf("failed to get RAM info: %w", err)
|
||||
}
|
||||
return memory, nil
|
||||
}
|
||||
Reference in New Issue
Block a user