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 }