Files

101 lines
2.7 KiB
Go
Raw Permalink Normal View History

2026-07-31 16:59:55 +08:00
package issuance
import (
"encoding/base64"
"fmt"
"time"
"github.com/google/uuid"
"git.apinb.com/ops/license/internal/signing"
"git.apinb.com/ops/license/internal/subject"
"git.apinb.com/ops/license/sdk/licence"
)
type FileSigner struct {
active *signing.ActiveSigner
}
func NewFileSigner(active *signing.ActiveSigner) (*FileSigner, error) {
if active == nil {
return nil, ErrInvalidInput
}
return &FileSigner{active: active}, nil
}
func (s *FileSigner) Build(item subject.Subject, input IssueInput, now time.Time) (licence.Claims, []byte, error) {
if s == nil || s.active == nil || item.ID == uuid.Nil {
return licence.Claims{}, nil, ErrInvalidInput
}
if input.ValidFrom.IsZero() || input.ExpiresOn.IsZero() {
return licence.Claims{}, nil, ErrInvalidDates
}
if hasNegativeQuota(input.Quotas) {
return licence.Claims{}, nil, ErrInvalidQuota
}
issuedOn, err := licence.NewDate(now)
if err != nil {
return licence.Claims{}, nil, fmt.Errorf("转换签发日期: %w", err)
}
validFrom, err := licence.NewDate(input.ValidFrom)
if err != nil {
return licence.Claims{}, nil, ErrInvalidDates
}
expiresOn, err := licence.NewDate(input.ExpiresOn)
if err != nil {
return licence.Claims{}, nil, ErrInvalidDates
}
validFromTime, err := validFrom.Time()
if err != nil {
return licence.Claims{}, nil, ErrInvalidDates
}
expiresOnTime, err := expiresOn.Time()
if err != nil || validFromTime.After(expiresOnTime) {
return licence.Claims{}, nil, ErrInvalidDates
}
licenceID, err := uuid.NewRandom()
if err != nil {
return licence.Claims{}, nil, fmt.Errorf("生成许可证 UUID v4: %w", err)
}
claims := licence.Claims{
ID: licenceID.String(),
PlatformName: item.PlatformName,
Workspace: item.Workspace,
IssuedOn: issuedOn,
ValidFrom: validFrom,
ExpiresOn: expiresOn,
Quotas: input.Quotas,
SigningKeyID: s.active.KeyID(),
}
signature, err := s.active.SignClaims(claims)
if err != nil {
return licence.Claims{}, nil, fmt.Errorf("签署许可证载荷: %w", err)
}
content, err := licence.MarshalEnvelope(licence.Envelope{
FormatVersion: 1,
Licence: claims,
SigningKeyCertificate: s.active.Certificate(),
Signature: base64.RawURLEncoding.EncodeToString(signature),
})
if err != nil {
return licence.Claims{}, nil, fmt.Errorf("编码许可证文件: %w", err)
}
return claims, content, nil
}
func hasNegativeQuota(quotas licence.Quotas) bool {
return quotas.MaxDatabase < 0 ||
quotas.MaxMiddleware < 0 ||
quotas.MaxNetworkDevice < 0 ||
quotas.MaxSecurity < 0 ||
quotas.MaxStorage < 0 ||
quotas.MaxPC < 0 ||
quotas.MaxServer < 0 ||
quotas.MaxUser < 0 ||
quotas.MaxRole < 0 ||
quotas.MaxPermission < 0 ||
quotas.MaxMenu < 0
}