Отпечаток сервера для сервера лицензий: internal/hwid (machine-id, UUID платформы через /etc/bj/hw-id от установщика, MAC), передаётся при активации и продлении
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user