diff --git a/match.go b/match.go index 950ef23..afeb7f6 100644 --- a/match.go +++ b/match.go @@ -63,11 +63,11 @@ func matchStatement(statement Statement, node ipld.Node) bool { } return isOrdered(s.Value(), one, lte) } - case Kind_Negation: + case Kind_Not: if s, ok := statement.(NegationStatement); ok { return !matchStatement(s.Value(), node) } - case Kind_Conjunction: + case Kind_And: if s, ok := statement.(ConjunctionStatement); ok { for _, cs := range s.Value() { r := matchStatement(cs, node) @@ -77,7 +77,7 @@ func matchStatement(statement Statement, node ipld.Node) bool { } return true } - case Kind_Disjunction: + case Kind_Or: if s, ok := statement.(DisjunctionStatement); ok { if len(s.Value()) == 0 { return true @@ -90,9 +90,20 @@ func matchStatement(statement Statement, node ipld.Node) bool { } return false } - case Kind_Wildcard: - case Kind_Universal: - case Kind_Existential: + case Kind_Like: + if s, ok := statement.(WildcardStatement); ok { + one, _, err := selector.Select(s.Selector(), node) + if err != nil || one == nil { + return false + } + v, err := one.AsString() + if err != nil { + return false + } + return s.Value().Match(v) + } + case Kind_All: + case Kind_Any: } panic(fmt.Errorf("unimplemented statement kind: %s", statement.Kind())) } diff --git a/match_test.go b/match_test.go index 183f1bf..59d9141 100644 --- a/match_test.go +++ b/match_test.go @@ -1,8 +1,10 @@ package policy import ( + "fmt" "testing" + "github.com/gobwas/glob" "github.com/ipfs/go-cid" cidlink "github.com/ipld/go-ipld-prime/linking/cid" "github.com/ipld/go-ipld-prime/node/basicnode" @@ -284,4 +286,49 @@ func TestMatch(t *testing.T) { ok = Match(pol, nd) require.True(t, ok) }) + + t.Run("wildcard", func(t *testing.T) { + glb, err := glob.Compile(`Alice\*, Bob*, Carol.`) + require.NoError(t, err) + + for _, s := range []string{ + "Alice*, Bob, Carol.", + "Alice*, Bob, Dan, Erin, Carol.", + "Alice*, Bob , Carol.", + "Alice*, Bob*, Carol.", + } { + func(s string) { + t.Run(fmt.Sprintf("pass %s", s), func(t *testing.T) { + np := basicnode.Prototype.String + nb := np.NewBuilder() + nb.AssignString(s) + nd := nb.Build() + + pol := Policy{Like(selector.MustParse("."), glb)} + ok := Match(pol, nd) + require.True(t, ok) + }) + }(s) + } + + for _, s := range []string{ + "Alice*, Bob, Carol", + "Alice*, Bob*, Carol!", + "Alice, Bob, Carol.", + " Alice*, Bob, Carol. ", + } { + func(s string) { + t.Run(fmt.Sprintf("fail %s", s), func(t *testing.T) { + np := basicnode.Prototype.String + nb := np.NewBuilder() + nb.AssignString(s) + nd := nb.Build() + + pol := Policy{Like(selector.MustParse("."), glb)} + ok := Match(pol, nd) + require.False(t, ok) + }) + }(s) + } + }) } diff --git a/policy.go b/policy.go index 26201fa..b03bf5a 100644 --- a/policy.go +++ b/policy.go @@ -3,6 +3,7 @@ package policy // https://github.com/ucan-wg/delegation/blob/4094d5878b58f5d35055a3b93fccda0b8329ebae/README.md#policy import ( + "github.com/gobwas/glob" "github.com/ipld/go-ipld-prime" "github.com/storacha-network/go-ucanto/core/policy/selector" ) @@ -13,12 +14,12 @@ const ( Kind_GreaterThanOrEqual = ">=" Kind_LessThan = "<" Kind_LessThanOrEqual = "<=" - Kind_Negation = "not" - Kind_Conjunction = "and" - Kind_Disjunction = "or" - Kind_Wildcard = "like" - Kind_Universal = "all" - Kind_Existential = "any" + Kind_Not = "not" + Kind_And = "and" + Kind_Or = "or" + Kind_Like = "like" + Kind_All = "all" + Kind_Any = "any" ) type Policy = []Statement @@ -42,7 +43,7 @@ type InequalityStatement interface { type WildcardStatement interface { Statement Selector() selector.Selector - Value() string + Value() glob.Glob } type ConnectiveStatement interface { @@ -113,7 +114,7 @@ type negation struct { } func (n negation) Kind() string { - return Kind_Negation + return Kind_Not } func (n negation) Value() Statement { @@ -129,7 +130,7 @@ type conjunction struct { } func (n conjunction) Kind() string { - return Kind_Conjunction + return Kind_And } func (n conjunction) Value() []Statement { @@ -145,7 +146,7 @@ type disjunction struct { } func (n disjunction) Kind() string { - return Kind_Disjunction + return Kind_Or } func (n disjunction) Value() []Statement { @@ -158,23 +159,23 @@ func Or(stmts ...Statement) DisjunctionStatement { type wildcard struct { selector selector.Selector - pattern string + glob glob.Glob } func (n wildcard) Kind() string { - return Kind_Wildcard + return Kind_Like } func (n wildcard) Selector() selector.Selector { return n.selector } -func (n wildcard) Value() string { - return n.pattern +func (n wildcard) Value() glob.Glob { + return n.glob } -func Like(selector selector.Selector, pattern string) WildcardStatement { - return wildcard{selector, pattern} +func Like(selector selector.Selector, glob glob.Glob) WildcardStatement { + return wildcard{selector, glob} } type quantifier struct { @@ -196,9 +197,9 @@ func (n quantifier) Value() Policy { } func All(selector selector.Selector, policy Policy) QuantifierStatement { - return quantifier{Kind_Universal, selector, policy} + return quantifier{Kind_All, selector, policy} } func Any(selector selector.Selector, policy Policy) QuantifierStatement { - return quantifier{Kind_Existential, selector, policy} + return quantifier{Kind_Any, selector, policy} }