mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package data
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"path"
 | 
						|
 | 
						|
	"github.com/docker/go/canonical/json"
 | 
						|
)
 | 
						|
 | 
						|
// SignedTargets is a fully unpacked targets.json, or target delegation
 | 
						|
// json file
 | 
						|
type SignedTargets struct {
 | 
						|
	Signatures []Signature
 | 
						|
	Signed     Targets
 | 
						|
	Dirty      bool
 | 
						|
}
 | 
						|
 | 
						|
// Targets is the Signed components of a targets.json or delegation json file
 | 
						|
type Targets struct {
 | 
						|
	SignedCommon
 | 
						|
	Targets     Files       `json:"targets"`
 | 
						|
	Delegations Delegations `json:"delegations,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// isValidTargetsStructure returns an error, or nil, depending on whether the content of the struct
 | 
						|
// is valid for targets metadata.  This does not check signatures or expiry, just that
 | 
						|
// the metadata content is valid.
 | 
						|
func isValidTargetsStructure(t Targets, roleName RoleName) error {
 | 
						|
	if roleName != CanonicalTargetsRole && !IsDelegation(roleName) {
 | 
						|
		return ErrInvalidRole{Role: roleName}
 | 
						|
	}
 | 
						|
 | 
						|
	// even if it's a delegated role, the metadata type is "Targets"
 | 
						|
	expectedType := TUFTypes[CanonicalTargetsRole]
 | 
						|
	if t.Type != expectedType {
 | 
						|
		return ErrInvalidMetadata{
 | 
						|
			role: roleName, msg: fmt.Sprintf("expected type %s, not %s", expectedType, t.Type)}
 | 
						|
	}
 | 
						|
 | 
						|
	if t.Version < 1 {
 | 
						|
		return ErrInvalidMetadata{role: roleName, msg: "version cannot be less than one"}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, roleObj := range t.Delegations.Roles {
 | 
						|
		if !IsDelegation(roleObj.Name) || path.Dir(roleObj.Name.String()) != roleName.String() {
 | 
						|
			return ErrInvalidMetadata{
 | 
						|
				role: roleName, msg: fmt.Sprintf("delegation role %s invalid", roleObj.Name)}
 | 
						|
		}
 | 
						|
		if err := isValidRootRoleStructure(roleName, roleObj.Name, roleObj.RootRole, t.Delegations.Keys); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// NewTargets intiializes a new empty SignedTargets object
 | 
						|
func NewTargets() *SignedTargets {
 | 
						|
	return &SignedTargets{
 | 
						|
		Signatures: make([]Signature, 0),
 | 
						|
		Signed: Targets{
 | 
						|
			SignedCommon: SignedCommon{
 | 
						|
				Type:    TUFTypes["targets"],
 | 
						|
				Version: 0,
 | 
						|
				Expires: DefaultExpires("targets"),
 | 
						|
			},
 | 
						|
			Targets:     make(Files),
 | 
						|
			Delegations: *NewDelegations(),
 | 
						|
		},
 | 
						|
		Dirty: true,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// GetMeta attempts to find the targets entry for the path. It
 | 
						|
// will return nil in the case of the target not being found.
 | 
						|
func (t SignedTargets) GetMeta(path string) *FileMeta {
 | 
						|
	for p, meta := range t.Signed.Targets {
 | 
						|
		if p == path {
 | 
						|
			return &meta
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GetValidDelegations filters the delegation roles specified in the signed targets, and
 | 
						|
// only returns roles that are direct children and restricts their paths
 | 
						|
func (t SignedTargets) GetValidDelegations(parent DelegationRole) []DelegationRole {
 | 
						|
	roles := t.buildDelegationRoles()
 | 
						|
	result := []DelegationRole{}
 | 
						|
	for _, r := range roles {
 | 
						|
		validRole, err := parent.Restrict(r)
 | 
						|
		if err != nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		result = append(result, validRole)
 | 
						|
	}
 | 
						|
	return result
 | 
						|
}
 | 
						|
 | 
						|
// BuildDelegationRole returns a copy of a DelegationRole using the information in this SignedTargets for the specified role name.
 | 
						|
// Will error for invalid role name or key metadata within this SignedTargets.  Path data is not validated.
 | 
						|
func (t *SignedTargets) BuildDelegationRole(roleName RoleName) (DelegationRole, error) {
 | 
						|
	for _, role := range t.Signed.Delegations.Roles {
 | 
						|
		if role.Name == roleName {
 | 
						|
			pubKeys := make(map[string]PublicKey)
 | 
						|
			for _, keyID := range role.KeyIDs {
 | 
						|
				pubKey, ok := t.Signed.Delegations.Keys[keyID]
 | 
						|
				if !ok {
 | 
						|
					// Couldn't retrieve all keys, so stop walking and return invalid role
 | 
						|
					return DelegationRole{}, ErrInvalidRole{
 | 
						|
						Role:   roleName,
 | 
						|
						Reason: "role lists unknown key " + keyID + " as a signing key",
 | 
						|
					}
 | 
						|
				}
 | 
						|
				pubKeys[keyID] = pubKey
 | 
						|
			}
 | 
						|
			return DelegationRole{
 | 
						|
				BaseRole: BaseRole{
 | 
						|
					Name:      role.Name,
 | 
						|
					Keys:      pubKeys,
 | 
						|
					Threshold: role.Threshold,
 | 
						|
				},
 | 
						|
				Paths: role.Paths,
 | 
						|
			}, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return DelegationRole{}, ErrNoSuchRole{Role: roleName}
 | 
						|
}
 | 
						|
 | 
						|
// helper function to create DelegationRole structures from all delegations in a SignedTargets,
 | 
						|
// these delegations are read directly from the SignedTargets and not modified or validated
 | 
						|
func (t SignedTargets) buildDelegationRoles() []DelegationRole {
 | 
						|
	var roles []DelegationRole
 | 
						|
	for _, roleData := range t.Signed.Delegations.Roles {
 | 
						|
		delgRole, err := t.BuildDelegationRole(roleData.Name)
 | 
						|
		if err != nil {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		roles = append(roles, delgRole)
 | 
						|
	}
 | 
						|
	return roles
 | 
						|
}
 | 
						|
 | 
						|
// AddTarget adds or updates the meta for the given path
 | 
						|
func (t *SignedTargets) AddTarget(path string, meta FileMeta) {
 | 
						|
	t.Signed.Targets[path] = meta
 | 
						|
	t.Dirty = true
 | 
						|
}
 | 
						|
 | 
						|
// AddDelegation will add a new delegated role with the given keys,
 | 
						|
// ensuring the keys either already exist, or are added to the map
 | 
						|
// of delegation keys
 | 
						|
func (t *SignedTargets) AddDelegation(role *Role, keys []*PublicKey) error {
 | 
						|
	return errors.New("Not Implemented")
 | 
						|
}
 | 
						|
 | 
						|
// ToSigned partially serializes a SignedTargets for further signing
 | 
						|
func (t *SignedTargets) ToSigned() (*Signed, error) {
 | 
						|
	s, err := defaultSerializer.MarshalCanonical(t.Signed)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	signed := json.RawMessage{}
 | 
						|
	err = signed.UnmarshalJSON(s)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	sigs := make([]Signature, len(t.Signatures))
 | 
						|
	copy(sigs, t.Signatures)
 | 
						|
	return &Signed{
 | 
						|
		Signatures: sigs,
 | 
						|
		Signed:     &signed,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalJSON returns the serialized form of SignedTargets as bytes
 | 
						|
func (t *SignedTargets) MarshalJSON() ([]byte, error) {
 | 
						|
	signed, err := t.ToSigned()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return defaultSerializer.Marshal(signed)
 | 
						|
}
 | 
						|
 | 
						|
// TargetsFromSigned fully unpacks a Signed object into a SignedTargets, given
 | 
						|
// a role name (so it can validate the SignedTargets object)
 | 
						|
func TargetsFromSigned(s *Signed, roleName RoleName) (*SignedTargets, error) {
 | 
						|
	t := Targets{}
 | 
						|
	if err := defaultSerializer.Unmarshal(*s.Signed, &t); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if err := isValidTargetsStructure(t, roleName); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	sigs := make([]Signature, len(s.Signatures))
 | 
						|
	copy(sigs, s.Signatures)
 | 
						|
	return &SignedTargets{
 | 
						|
		Signatures: sigs,
 | 
						|
		Signed:     t,
 | 
						|
	}, nil
 | 
						|
}
 |