2024-08-19 23:16:36 +02:00
|
|
|
package policy
|
|
|
|
|
|
|
|
|
|
// https://github.com/ucan-wg/delegation/blob/4094d5878b58f5d35055a3b93fccda0b8329ebae/README.md#policy
|
|
|
|
|
|
|
|
|
|
import (
|
2024-10-14 12:19:33 +02:00
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2024-08-20 15:55:04 +02:00
|
|
|
"github.com/ipld/go-ipld-prime"
|
2024-10-14 12:19:33 +02:00
|
|
|
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
2024-08-30 22:06:59 +02:00
|
|
|
|
2026-01-08 15:46:00 -05:00
|
|
|
selpkg "code.sonr.org/go/ucan/pkg/policy/selector"
|
2024-08-19 23:16:36 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2024-09-02 02:24:13 +02:00
|
|
|
KindEqual = "==" // implemented by equality
|
2025-01-22 14:12:41 +01:00
|
|
|
KindNotEqual = "!=" // implemented by equality
|
2024-09-02 02:24:13 +02:00
|
|
|
KindGreaterThan = ">" // implemented by equality
|
|
|
|
|
KindGreaterThanOrEqual = ">=" // implemented by equality
|
|
|
|
|
KindLessThan = "<" // implemented by equality
|
|
|
|
|
KindLessThanOrEqual = "<=" // implemented by equality
|
|
|
|
|
KindNot = "not" // implemented by negation
|
|
|
|
|
KindAnd = "and" // implemented by connective
|
|
|
|
|
KindOr = "or" // implemented by connective
|
|
|
|
|
KindLike = "like" // implemented by wildcard
|
|
|
|
|
KindAll = "all" // implemented by quantifier
|
|
|
|
|
KindAny = "any" // implemented by quantifier
|
2024-08-19 23:16:36 +02:00
|
|
|
)
|
|
|
|
|
|
2024-09-01 20:27:54 +02:00
|
|
|
type Policy []Statement
|
2024-08-19 23:16:36 +02:00
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
type Constructor func() (Statement, error)
|
|
|
|
|
|
|
|
|
|
func Construct(cstors ...Constructor) (Policy, error) {
|
|
|
|
|
stmts, err := assemble(cstors)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return stmts, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func MustConstruct(cstors ...Constructor) Policy {
|
|
|
|
|
pol, err := Construct(cstors...)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
return pol
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (p Policy) String() string {
|
|
|
|
|
if len(p) == 0 {
|
|
|
|
|
return "[]"
|
|
|
|
|
}
|
|
|
|
|
childs := make([]string, len(p))
|
|
|
|
|
for i, statement := range p {
|
|
|
|
|
childs[i] = strings.ReplaceAll(statement.String(), "\n", "\n ")
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("[\n %s\n]", strings.Join(childs, ",\n "))
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 23:16:36 +02:00
|
|
|
type Statement interface {
|
|
|
|
|
Kind() string
|
2024-10-14 12:19:33 +02:00
|
|
|
String() string
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type equality struct {
|
|
|
|
|
kind string
|
2024-10-14 20:09:21 +02:00
|
|
|
selector selpkg.Selector
|
2024-08-20 15:55:04 +02:00
|
|
|
value ipld.Node
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e equality) Kind() string {
|
|
|
|
|
return e.kind
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (e equality) String() string {
|
|
|
|
|
child, err := ipld.Encode(e.value, dagjson.Encode)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "ERROR: INVALID VALUE"
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf(`["%s", "%s", %s]`, e.kind, e.selector, strings.ReplaceAll(string(child), "\n", "\n "))
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func Equal(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindEqual, selector: sel, value: value}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-22 14:12:41 +01:00
|
|
|
func NotEqual(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindNotEqual, selector: sel, value: value}, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func GreaterThan(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindGreaterThan, selector: sel, value: value}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func GreaterThanOrEqual(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindGreaterThanOrEqual, selector: sel, value: value}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func LessThan(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindLessThan, selector: sel, value: value}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func LessThanOrEqual(selector string, value ipld.Node) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return equality{kind: KindLessThanOrEqual, selector: sel, value: value}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type negation struct {
|
|
|
|
|
statement Statement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n negation) Kind() string {
|
2024-09-01 17:06:21 +02:00
|
|
|
return KindNot
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (n negation) String() string {
|
|
|
|
|
child := n.statement.String()
|
2025-01-22 14:12:41 +01:00
|
|
|
return fmt.Sprintf(`["%s", %s]`, n.Kind(), strings.ReplaceAll(child, "\n", "\n "))
|
2024-10-14 12:19:33 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func Not(cstor Constructor) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
stmt, err := cstor()
|
|
|
|
|
return negation{statement: stmt}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-01 20:27:54 +02:00
|
|
|
type connective struct {
|
|
|
|
|
kind string
|
2024-08-19 23:16:36 +02:00
|
|
|
statements []Statement
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-01 20:27:54 +02:00
|
|
|
func (c connective) Kind() string {
|
|
|
|
|
return c.kind
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (c connective) String() string {
|
|
|
|
|
childs := make([]string, len(c.statements))
|
|
|
|
|
for i, statement := range c.statements {
|
|
|
|
|
childs[i] = strings.ReplaceAll(statement.String(), "\n", "\n ")
|
|
|
|
|
}
|
2025-01-22 14:12:41 +01:00
|
|
|
return fmt.Sprintf("[\"%s\", [\n %s\n]]", c.kind, strings.Join(childs, ",\n "))
|
2024-10-14 12:19:33 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func And(cstors ...Constructor) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
stmts, err := assemble(cstors)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return connective{kind: KindAnd, statements: stmts}, nil
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func Or(cstors ...Constructor) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
stmts, err := assemble(cstors)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return connective{kind: KindOr, statements: stmts}, nil
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type wildcard struct {
|
2024-10-14 20:09:21 +02:00
|
|
|
selector selpkg.Selector
|
2024-09-18 11:24:37 +02:00
|
|
|
pattern glob
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n wildcard) Kind() string {
|
2024-09-01 17:06:21 +02:00
|
|
|
return KindLike
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (n wildcard) String() string {
|
|
|
|
|
return fmt.Sprintf(`["%s", "%s", "%s"]`, n.Kind(), n.selector, n.pattern)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func Like(selector string, pattern string) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
g, err := parseGlob(pattern)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return wildcard{selector: sel, pattern: g}, err
|
2024-10-14 12:19:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 23:16:36 +02:00
|
|
|
type quantifier struct {
|
2024-09-04 15:58:08 +02:00
|
|
|
kind string
|
2024-10-14 20:09:21 +02:00
|
|
|
selector selpkg.Selector
|
2024-09-04 15:58:08 +02:00
|
|
|
statement Statement
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (n quantifier) Kind() string {
|
|
|
|
|
return n.kind
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-14 12:19:33 +02:00
|
|
|
func (n quantifier) String() string {
|
|
|
|
|
child := n.statement.String()
|
2025-01-22 14:12:41 +01:00
|
|
|
return fmt.Sprintf("[\"%s\", \"%s\",\n %s\n]", n.Kind(), n.selector, strings.ReplaceAll(child, "\n", "\n "))
|
2024-10-14 12:19:33 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func All(selector string, cstor Constructor) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
stmt, err := cstor()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return quantifier{kind: KindAll, selector: sel, statement: stmt}, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Any(selector string, cstor Constructor) Constructor {
|
|
|
|
|
return func() (Statement, error) {
|
|
|
|
|
stmt, err := cstor()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
sel, err := selpkg.Parse(selector)
|
|
|
|
|
return quantifier{kind: KindAny, selector: sel, statement: stmt}, err
|
|
|
|
|
}
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-14 20:09:21 +02:00
|
|
|
func assemble(cstors []Constructor) ([]Statement, error) {
|
|
|
|
|
stmts := make([]Statement, 0, len(cstors))
|
|
|
|
|
for _, cstor := range cstors {
|
|
|
|
|
stmt, err := cstor()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
stmts = append(stmts, stmt)
|
|
|
|
|
}
|
|
|
|
|
return stmts, nil
|
2024-08-19 23:16:36 +02:00
|
|
|
}
|