Files
motr-enclave/internal/crypto/ucan/policy.go

214 lines
6.8 KiB
Go

package ucan
import (
"code.sonr.org/go/ucan/pkg/policy"
"code.sonr.org/go/ucan/pkg/policy/literal"
"github.com/ipld/go-ipld-prime"
)
// PolicyBuilder provides a fluent API for constructing UCAN policies.
// Policies are arrays of statements that form an implicit AND.
type PolicyBuilder struct {
constructors []policy.Constructor
}
// NewPolicy creates a new PolicyBuilder.
func NewPolicy() *PolicyBuilder {
return &PolicyBuilder{
constructors: make([]policy.Constructor, 0),
}
}
// Build constructs the final Policy from all added statements.
func (b *PolicyBuilder) Build() (Policy, error) {
return policy.Construct(b.constructors...)
}
// MustBuild constructs the final Policy, panicking on error.
func (b *PolicyBuilder) MustBuild() Policy {
return policy.MustConstruct(b.constructors...)
}
// Equal adds an equality constraint: selector == value
func (b *PolicyBuilder) Equal(selector string, value any) *PolicyBuilder {
node, err := toIPLDNode(value)
if err != nil {
// Store error for Build() to return
b.constructors = append(b.constructors, func() (policy.Statement, error) {
return nil, err
})
return b
}
b.constructors = append(b.constructors, policy.Equal(selector, node))
return b
}
// NotEqual adds an inequality constraint: selector != value
func (b *PolicyBuilder) NotEqual(selector string, value any) *PolicyBuilder {
node, err := toIPLDNode(value)
if err != nil {
b.constructors = append(b.constructors, func() (policy.Statement, error) {
return nil, err
})
return b
}
b.constructors = append(b.constructors, policy.NotEqual(selector, node))
return b
}
// GreaterThan adds a comparison constraint: selector > value
func (b *PolicyBuilder) GreaterThan(selector string, value int64) *PolicyBuilder {
b.constructors = append(b.constructors, policy.GreaterThan(selector, literal.Int(value)))
return b
}
// GreaterThanOrEqual adds a comparison constraint: selector >= value
func (b *PolicyBuilder) GreaterThanOrEqual(selector string, value int64) *PolicyBuilder {
b.constructors = append(b.constructors, policy.GreaterThanOrEqual(selector, literal.Int(value)))
return b
}
// LessThan adds a comparison constraint: selector < value
func (b *PolicyBuilder) LessThan(selector string, value int64) *PolicyBuilder {
b.constructors = append(b.constructors, policy.LessThan(selector, literal.Int(value)))
return b
}
// LessThanOrEqual adds a comparison constraint: selector <= value
func (b *PolicyBuilder) LessThanOrEqual(selector string, value int64) *PolicyBuilder {
b.constructors = append(b.constructors, policy.LessThanOrEqual(selector, literal.Int(value)))
return b
}
// Like adds a glob pattern constraint: selector matches pattern
// Use * for wildcard, \* for literal asterisk.
func (b *PolicyBuilder) Like(selector, pattern string) *PolicyBuilder {
b.constructors = append(b.constructors, policy.Like(selector, pattern))
return b
}
// Not negates a statement
func (b *PolicyBuilder) Not(stmt policy.Constructor) *PolicyBuilder {
b.constructors = append(b.constructors, policy.Not(stmt))
return b
}
// And adds a logical AND of multiple statements
func (b *PolicyBuilder) And(stmts ...policy.Constructor) *PolicyBuilder {
b.constructors = append(b.constructors, policy.And(stmts...))
return b
}
// Or adds a logical OR of multiple statements
func (b *PolicyBuilder) Or(stmts ...policy.Constructor) *PolicyBuilder {
b.constructors = append(b.constructors, policy.Or(stmts...))
return b
}
// All adds a universal quantifier: all elements at selector must satisfy statement
func (b *PolicyBuilder) All(selector string, stmt policy.Constructor) *PolicyBuilder {
b.constructors = append(b.constructors, policy.All(selector, stmt))
return b
}
// Any adds an existential quantifier: at least one element at selector must satisfy statement
func (b *PolicyBuilder) Any(selector string, stmt policy.Constructor) *PolicyBuilder {
b.constructors = append(b.constructors, policy.Any(selector, stmt))
return b
}
// toIPLDNode converts a Go value to an IPLD node for policy evaluation.
func toIPLDNode(value any) (ipld.Node, error) {
// Handle IPLD nodes directly
if node, ok := value.(ipld.Node); ok {
return node, nil
}
// Use literal package for conversion
return literal.Any(value)
}
// --- Sonr-specific Policy Helpers ---
// VaultPolicy creates a policy that restricts operations to a specific vault.
// The vault is identified by its CID.
func VaultPolicy(vaultCID string) Policy {
return NewPolicy().Equal(".vault", vaultCID).MustBuild()
}
// DIDPolicy creates a policy that restricts operations to DIDs matching a pattern.
// Use glob patterns: "did:sonr:*" matches all Sonr DIDs.
func DIDPolicy(didPattern string) Policy {
return NewPolicy().Like(".did", didPattern).MustBuild()
}
// ChainPolicy creates a policy that restricts operations to a specific chain.
func ChainPolicy(chainID string) Policy {
return NewPolicy().Equal(".chain_id", chainID).MustBuild()
}
// AccountPolicy creates a policy that restricts operations to a specific account address.
func AccountPolicy(address string) Policy {
return NewPolicy().Equal(".address", address).MustBuild()
}
// RecordTypePolicy creates a policy for DWN operations on specific record types.
func RecordTypePolicy(recordType string) Policy {
return NewPolicy().Equal(".record_type", recordType).MustBuild()
}
// CombinePolicies merges multiple policies into one (implicit AND).
func CombinePolicies(policies ...Policy) Policy {
combined := make(Policy, 0)
for _, p := range policies {
combined = append(combined, p...)
}
return combined
}
// EmptyPolicy returns an empty policy (no constraints).
func EmptyPolicy() Policy {
return Policy{}
}
// --- Policy Constructor Helpers ---
// These return policy.Constructor for use with And/Or/Not/All/Any
// EqualTo creates an equality constructor for nested policy building.
func EqualTo(selector string, value any) policy.Constructor {
return func() (policy.Statement, error) {
node, err := toIPLDNode(value)
if err != nil {
return nil, err
}
return policy.Equal(selector, node)()
}
}
// NotEqualTo creates an inequality constructor for nested policy building.
func NotEqualTo(selector string, value any) policy.Constructor {
return func() (policy.Statement, error) {
node, err := toIPLDNode(value)
if err != nil {
return nil, err
}
return policy.NotEqual(selector, node)()
}
}
// Matches creates a glob pattern constructor for nested policy building.
func Matches(selector, pattern string) policy.Constructor {
return policy.Like(selector, pattern)
}
// GreaterThanValue creates a comparison constructor.
func GreaterThanValue(selector string, value int64) policy.Constructor {
return policy.GreaterThan(selector, literal.Int(value))
}
// LessThanValue creates a comparison constructor.
func LessThanValue(selector string, value int64) policy.Constructor {
return policy.LessThan(selector, literal.Int(value))
}