// Package hwid — отпечаток сервера для сервера лицензий: хэши (sha256) трёх признаков, сами // значения никуда не передаются. По ним сервер лицензий узнаёт один и тот же сервер у разных // организаций (защита от «отключил лицензию у одной компании — включил у другой»). // - machine: /etc/machine-id — меняется при переустановке ОС; // - board: UUID платформы (BIOS / гипервизор, /sys/class/dmi/id/product_uuid) — у виртуальной // машины сохраняется при переустановке ОС; читается только root, поэтому установщик кладёт // его хэш в /etc/bj/hw-id, а bj читает оттуда; // - mac: MAC-адреса сетевых карт (физических и virtio), отсортированные. package hwid import ( "crypto/sha256" "encoding/hex" "os" "path/filepath" "sort" "strings" ) // CacheFile — хэш UUID платформы, записанный установщиком (root) для bj. const CacheFile = "/etc/bj/hw-id" func sum(s string) string { s = strings.TrimSpace(s) if s == "" { return "" } h := sha256.Sum256([]byte(s)) return hex.EncodeToString(h[:]) } // Machine — хэш /etc/machine-id. func Machine() string { b, _ := os.ReadFile("/etc/machine-id") return sum(string(b)) } // Board — хэш UUID платформы: из DMI (под root) или из файла, записанного установщиком. func Board() string { if b, err := os.ReadFile("/sys/class/dmi/id/product_uuid"); err == nil { if v := strings.ToLower(strings.TrimSpace(string(b))); v != "" && v != "00000000-0000-0000-0000-000000000000" { return sum(v) } } b, _ := os.ReadFile(CacheFile) return strings.TrimSpace(string(b)) } // MAC — хэш отсортированных MAC-адресов сетевых карт, у которых есть устройство (не lo, не мосты). func MAC() string { ents, _ := os.ReadDir("/sys/class/net") var macs []string for _, e := range ents { dir := filepath.Join("/sys/class/net", e.Name()) if _, err := os.Stat(filepath.Join(dir, "device")); err != nil { continue } b, err := os.ReadFile(filepath.Join(dir, "address")) if a := strings.ToLower(strings.TrimSpace(string(b))); err == nil && a != "" && a != "00:00:00:00:00:00" { macs = append(macs, a) } } sort.Strings(macs) return sum(strings.Join(macs, ",")) } // WriteCache — записать хэш UUID платформы для bj (вызывает установщик под root). func WriteCache(root string) error { b := Board() if b == "" { return nil } p := filepath.Join(root, CacheFile) if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { return err } return os.WriteFile(p, []byte(b+"\n"), 0o644) }