// GetDelegation finds the role entry representing the provided // role name or ErrInvalidRole func (tr *Repo) GetDelegation(role string) (*data.Role, error) { r := data.Role{Name: role} if !r.IsDelegation() { return nil, data.ErrInvalidRole{Role: role, Reason: "not a valid delegated role"} } parent := path.Dir(role) // check the parent role if parentRole := tr.keysDB.GetRole(parent); parentRole == nil { return nil, data.ErrInvalidRole{Role: role, Reason: "parent role not found"} } // check the parent role's metadata p, ok := tr.Targets[parent] if !ok { // the parent targetfile may not exist yet, so it can't be in the list return nil, data.ErrNoSuchRole{Role: role} } foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, role) if foundAt < 0 { return nil, data.ErrNoSuchRole{Role: role} } return p.Signed.Delegations.Roles[foundAt], nil }
// UpdateDelegations updates the appropriate delegations, either adding // a new delegation or updating an existing one. If keys are // provided, the IDs will be added to the role (if they do not exist // there already), and the keys will be added to the targets file. func (tr *Repo) UpdateDelegations(role *data.Role, keys []data.PublicKey) error { if !role.IsDelegation() || !role.IsValid() { return data.ErrInvalidRole{Role: role.Name, Reason: "not a valid delegated role"} } parent := path.Dir(role.Name) if err := tr.VerifyCanSign(parent); err != nil { return err } // check the parent role's metadata p, ok := tr.Targets[parent] if !ok { // the parent targetfile may not exist yet - if not, then create it var err error p, err = tr.InitTargets(parent) if err != nil { return err } } for _, k := range keys { if !utils.StrSliceContains(role.KeyIDs, k.ID()) { role.KeyIDs = append(role.KeyIDs, k.ID()) } p.Signed.Delegations.Keys[k.ID()] = k tr.keysDB.AddKey(k) } // if the role has fewer keys than the threshold, it // will never be able to create a valid targets file // and should be considered invalid. if len(role.KeyIDs) < role.Threshold { return data.ErrInvalidRole{Role: role.Name, Reason: "insufficient keys to meet threshold"} } foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, role.Name) if foundAt >= 0 { p.Signed.Delegations.Roles[foundAt] = role } else { p.Signed.Delegations.Roles = append(p.Signed.Delegations.Roles, role) } // We've made a change to parent. Set it to dirty p.Dirty = true // We don't actually want to create the new delegation metadata yet. // When we add a delegation, it may only be signable by a key we don't have // (hence we are delegating signing). tr.keysDB.AddRole(role) utils.RemoveUnusedKeys(p) return nil }
// InitTargets initializes an empty targets, and returns the new empty target func (tr *Repo) InitTargets(role string) (*data.SignedTargets, error) { r := data.Role{Name: role} if !r.IsDelegation() && role != data.CanonicalTargetsRole { return nil, data.ErrInvalidRole{ Role: role, Reason: fmt.Sprintf("role is not a valid targets role name: %s", role), } } targets := data.NewTargets() tr.Targets[role] = targets return targets, nil }
// DeleteDelegation removes a delegated targets role from its parent // targets object. It also deletes the delegation from the snapshot. // DeleteDelegation will only make use of the role Name field. func (tr *Repo) DeleteDelegation(role data.Role) error { if !role.IsDelegation() { return data.ErrInvalidRole{Role: role.Name, Reason: "not a valid delegated role"} } // the role variable must not be used past this assignment for safety name := role.Name parent := path.Dir(name) if err := tr.VerifyCanSign(parent); err != nil { return err } // delete delegated data from Targets map and Snapshot - if they don't // exist, these are no-op delete(tr.Targets, name) tr.Snapshot.DeleteMeta(name) p, ok := tr.Targets[parent] if !ok { // if there is no parent metadata (the role exists though), then this // is as good as done. return nil } foundAt := utils.FindRoleIndex(p.Signed.Delegations.Roles, name) if foundAt >= 0 { var roles []*data.Role // slice out deleted role roles = append(roles, p.Signed.Delegations.Roles[:foundAt]...) if foundAt+1 < len(p.Signed.Delegations.Roles) { roles = append(roles, p.Signed.Delegations.Roles[foundAt+1:]...) } p.Signed.Delegations.Roles = roles utils.RemoveUnusedKeys(p) p.Dirty = true } // if the role wasn't found, it's a good as deleted return nil }
// UpdateDelegations updates the appropriate delegations, either adding // a new delegation or updating an existing one. If keys are // provided, the IDs will be added to the role (if they do not exist // there already), and the keys will be added to the targets file. // The "before" argument specifies another role which this new role // will be added in front of (i.e. higher priority) in the delegation list. // An empty before string indicates to add the role to the end of the // delegation list. // A new, empty, targets file will be created for the new role. func (tr *Repo) UpdateDelegations(role *data.Role, keys []data.PublicKey, before string) error { if !role.IsDelegation() || !role.IsValid() { return data.ErrInvalidRole{Role: role.Name} } parent := filepath.Dir(role.Name) p, ok := tr.Targets[parent] if !ok { return data.ErrInvalidRole{Role: role.Name} } for _, k := range keys { if !utils.StrSliceContains(role.KeyIDs, k.ID()) { role.KeyIDs = append(role.KeyIDs, k.ID()) } p.Signed.Delegations.Keys[k.ID()] = k tr.keysDB.AddKey(k) } i := -1 var r *data.Role for i, r = range p.Signed.Delegations.Roles { if r.Name == role.Name { break } } if i >= 0 { p.Signed.Delegations.Roles[i] = role } else { p.Signed.Delegations.Roles = append(p.Signed.Delegations.Roles, role) } p.Dirty = true roleTargets := data.NewTargets() // NewTargets always marked Dirty tr.Targets[role.Name] = roleTargets tr.keysDB.AddRole(role) return nil }