first commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package lexicomai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// License — содержимое license.json продукта. Формат (подтверждён на прод-боксе):
|
||||
//
|
||||
// { "service": "cls", "expire": "2045-01-01", "licenses": 0, "key": "50e1...9cf" }
|
||||
//
|
||||
// Key — подписанная последовательность (service+expire+licenses+uuid), её
|
||||
// генерация — на стороне вендора; модуль только валидирует и применяет.
|
||||
type License struct {
|
||||
Service string `json:"service"`
|
||||
Expire string `json:"expire"`
|
||||
Licenses int `json:"licenses"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// ParseLicense разбирает license.json. Отсутствующий файл — доменная ошибка
|
||||
// (из неё инструмент делает понятный errorResult).
|
||||
func ParseLicense(data []byte) (*License, error) {
|
||||
var l License
|
||||
if err := json.Unmarshal(data, &l); err != nil {
|
||||
return nil, fmt.Errorf("parse license: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(l.Service) == "" {
|
||||
return nil, fmt.Errorf("license: service is empty")
|
||||
}
|
||||
if strings.TrimSpace(l.Expire) == "" {
|
||||
return nil, fmt.Errorf("license: expire is empty")
|
||||
}
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
// VerifyFields проверяет поля лицензии без обращения к сервису: привязана ли
|
||||
// она к нужному продукту и не истекла ли. Возвращает список замечаний (пустой —
|
||||
// поля корректны).
|
||||
func (l *License) VerifyFields(product string) []string {
|
||||
var notes []string
|
||||
if strings.TrimSpace(l.Service) != product {
|
||||
notes = append(notes, fmt.Sprintf("license bound to %q, wanted %q", l.Service, product))
|
||||
}
|
||||
if exp, err := time.Parse("2006-01-02", l.Expire); err == nil {
|
||||
if time.Now().After(exp) {
|
||||
notes = append(notes, fmt.Sprintf("license expired on %s", l.Expire))
|
||||
}
|
||||
} else {
|
||||
notes = append(notes, fmt.Sprintf("license expire %q is not YYYY-MM-DD", l.Expire))
|
||||
}
|
||||
if l.Licenses == 0 {
|
||||
notes = append(notes, "license has 0 seats")
|
||||
}
|
||||
return notes
|
||||
}
|
||||
|
||||
// KeyMasked возвращает ключ лицензии с маской — полный key не выводим
|
||||
// (может быть чувствительным). Короткие ключи скрываются целиком.
|
||||
func (l *License) KeyMasked() string {
|
||||
k := strings.TrimSpace(l.Key)
|
||||
if k == "" {
|
||||
return ""
|
||||
}
|
||||
if len(k) <= 6 {
|
||||
return "***"
|
||||
}
|
||||
return k[:3] + "…" + k[len(k)-3:]
|
||||
}
|
||||
Reference in New Issue
Block a user