90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
package licence
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
func Verify(content []byte, expected Subject) (*Licence, error) {
|
|
envelope, err := Parse(content)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := validateQuotas(envelope.Licence.Quotas); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
publicKey, err := VerifySigningKeyCertificate(envelope.SigningKeyCertificate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
licenceSigningKeyID, err := parseUUID(envelope.Licence.SigningKeyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 签发密钥 ID 格式错误", ErrMalformedFile)
|
|
}
|
|
certificateKeyID, err := parseUUID(envelope.SigningKeyCertificate.KeyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 凭证密钥 ID 格式错误", ErrInvalidKeyCertificate)
|
|
}
|
|
if licenceSigningKeyID != certificateKeyID {
|
|
return nil, fmt.Errorf("%w: 签发密钥 ID 不一致", ErrInvalidKeyCertificate)
|
|
}
|
|
|
|
message, err := ClaimsMessage(envelope.Licence)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
signature, err := decodeBase64URL(envelope.Signature, ed25519.SignatureSize)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 许可证签名格式错误", ErrMalformedFile)
|
|
}
|
|
if !ed25519.Verify(publicKey, message, signature) {
|
|
return nil, ErrInvalidSignature
|
|
}
|
|
|
|
if envelope.Licence.PlatformName != expected.PlatformName || envelope.Licence.Workspace != expected.Workspace {
|
|
return nil, ErrSubjectMismatch
|
|
}
|
|
return verifiedLicenceForDate(envelope.Licence, time.Now())
|
|
}
|
|
|
|
func verifiedLicenceForDate(claims Claims, now time.Time) (*Licence, error) {
|
|
issuedOn, err := claims.IssuedOn.Time()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 签发日期格式错误", ErrMalformedFile)
|
|
}
|
|
validFrom, err := claims.ValidFrom.Time()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 生效日期格式错误", ErrMalformedFile)
|
|
}
|
|
expiresOn, err := claims.ExpiresOn.Time()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 到期日期格式错误", ErrMalformedFile)
|
|
}
|
|
location, err := locationShanghai()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: 无法加载日期时区", ErrMalformedFile)
|
|
}
|
|
now = now.In(location)
|
|
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, location)
|
|
if today.Before(validFrom) {
|
|
return nil, ErrNotYetValid
|
|
}
|
|
if today.After(expiresOn) {
|
|
return nil, ErrExpired
|
|
}
|
|
|
|
return &Licence{
|
|
ID: claims.ID,
|
|
Subject: Subject{
|
|
PlatformName: claims.PlatformName,
|
|
Workspace: claims.Workspace,
|
|
},
|
|
IssuedOn: issuedOn,
|
|
ValidFrom: validFrom,
|
|
ExpiresOn: expiresOn,
|
|
Quotas: claims.Quotas,
|
|
}, nil
|
|
}
|