feat(license): dual-path opsx-licence client alongside HMAC
Wire LIC-/LICOFF- activate/verify/heartbeat to licence.rlwj.cn/api, keep legacy HMAC accepted with deprecation banner, add instance_id fingerprint and licensing docs (product lokistack still needs admin create).
This commit is contained in:
1 parent
5f42d9f696
commit
af0298e994
13 files changed
+888
-37
No files matched your search
@@ -0,0 +1,45 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"lokistack/config"
|
||||
)
|
||||
|
||||
// instance_id 是部署实例指纹:持久化到 DATA_DIR/instance.id,不含邮箱/姓名等 PII。
|
||||
// 对齐 OpsxShell device_id 语义,供 opsx-licence 按实例占座。
|
||||
|
||||
var (
|
||||
instanceIDOnce sync.Once
|
||||
instanceIDVal string
|
||||
)
|
||||
|
||||
// GetOrCreateInstanceID 返回稳定实例 ID(机器/安装指纹)。
|
||||
func GetOrCreateInstanceID() string {
|
||||
instanceIDOnce.Do(func() {
|
||||
cfg := config.GetConfig()
|
||||
path := filepath.Join(cfg.DataDir, "instance.id")
|
||||
if raw, err := os.ReadFile(path); err == nil {
|
||||
id := strings.TrimSpace(string(raw))
|
||||
if id != "" {
|
||||
instanceIDVal = id
|
||||
return
|
||||
}
|
||||
}
|
||||
buf := make([]byte, 16)
|
||||
if _, err := rand.Read(buf); err != nil {
|
||||
instanceIDVal = "lokistack-fallback-instance"
|
||||
return
|
||||
}
|
||||
id := "ls-" + hex.EncodeToString(buf)
|
||||
_ = os.MkdirAll(cfg.DataDir, 0o700)
|
||||
_ = os.WriteFile(path, []byte(id+"\n"), 0o600)
|
||||
instanceIDVal = id
|
||||
})
|
||||
return instanceIDVal
|
||||
}
|
||||
Reference in new issue
Block a user