Skip to content

Commit

Permalink
confdb,asserts,daemon: add confdb-control api
Browse files Browse the repository at this point in the history
  • Loading branch information
st3v3nmw committed Dec 20, 2024
1 parent 08d3c8d commit 1ed5ca7
Show file tree
Hide file tree
Showing 7 changed files with 879 additions and 60 deletions.
89 changes: 88 additions & 1 deletion asserts/confdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"time"

"github.com/snapcore/snapd/confdb"
Expand Down Expand Up @@ -119,6 +120,22 @@ type ConfdbControl struct {
operators map[string]*confdb.Operator
}

// NewConfdbControl returns an empty confdb-control assertion.
func NewConfdbControl(serial *Serial) *ConfdbControl {
return &ConfdbControl{
assertionBase: assertionBase{
headers: map[string]interface{}{
"type": "confdb-control",
"brand-id": serial.BrandID(),
"model": serial.Model(),
"serial": serial.Serial(),
"groups": []interface{}{},
},
},
operators: map[string]*confdb.Operator{},
}

Check warning on line 136 in asserts/confdb.go

View check run for this annotation

Codecov / codecov/patch

asserts/confdb.go#L124-L136

Added lines #L124 - L136 were not covered by tests
}

// BrandID returns the brand identifier of the device.
func (cc *ConfdbControl) BrandID() string {
return cc.HeaderString("brand-id")
Expand All @@ -135,6 +152,76 @@ func (cc *ConfdbControl) Serial() string {
return cc.HeaderString("serial")
}

// IsDelegated checks if the view is delegated to the operator with the given auth.
func (cc *ConfdbControl) IsDelegated(operatorID, view string, auth []string) (bool, error) {
operator, ok := cc.operators[operatorID]
if !ok {
return false, nil // nothing is delegated to this operator
}

return operator.IsDelegated(view, auth)
}

// Delegate delegates the given views with the provided auth to the operator.
func (cc *ConfdbControl) Delegate(operatorID string, views, auth []string) error {
operator, ok := cc.operators[operatorID]
if !ok {
operator = &confdb.Operator{ID: operatorID}
}

err := operator.Delegate(views, auth)
if err != nil {
return err
}

cc.operators[operatorID] = operator
return nil
}

// Revoke withdraws access to the views that have been delegated with the provided auth.
func (cc *ConfdbControl) Revoke(operatorID string, views, auth []string) error {
operator, ok := cc.operators[operatorID]
if !ok {
return nil // nothing is delegated to this operator
}

if len(views) == 0 && len(auth) == 0 {
delete(cc.operators, operatorID) // completely revoke access from this operator
return nil
}

return operator.Revoke(views, auth)
}

// Groups returns the groups in the raw assertion's format.
func (cc *ConfdbControl) Groups() []interface{} {
ids := make([]string, 0, len(cc.operators))
for id := range cc.operators {
ids = append(ids, id)
}
sort.Strings(ids)

var groups []interface{}
for _, id := range ids { // sort by operator
op := cc.operators[id]
for _, group := range op.Groups {
auth, views := []interface{}{}, []interface{}{}
for _, a := range group.Authentication {
auth = append(auth, string(a))
}

for _, v := range group.Views {
views = append(views, v.String())
}

groups = append(groups, map[string]interface{}{
"operator-id": op.ID, "authentication": auth, "views": views,
})
}
}
return groups
}

// assembleConfdbControl creates a new confdb-control assertion after validating
// all required fields and constraints.
func assembleConfdbControl(assert assertionBase) (Assertion, error) {
Expand Down Expand Up @@ -209,7 +296,7 @@ func parseConfdbControlGroups(rawGroups []interface{}) (map[string]*confdb.Opera
return nil, fmt.Errorf(`%s: "views" must be provided`, errPrefix)
}

if err := operator.AddControlGroup(views, auth); err != nil {
if err := operator.Delegate(views, auth); err != nil {
return nil, fmt.Errorf(`%s: %w`, errPrefix, err)
}
}
Expand Down
Loading

0 comments on commit 1ed5ca7

Please sign in to comment.