101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
|
|
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
|
||
|
|
}
|