72 lines
2.5 KiB
Go
72 lines
2.5 KiB
Go
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:]
|
|
}
|