-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatcher.go
130 lines (111 loc) · 3.62 KB
/
matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package vanguard
import (
"regexp"
"strings"
"sync"
"github.com/srikrsna/glob"
)
// ResourceMatcher is used to match resources.
//
// There are the following strategies already implemented,
// * Exact
// * Prefix
// * Regex
// * Glob
type ResourceMatcher interface {
MatchResource(has, need string) (bool, error)
}
// ResourceMatcher is used to match permission levels.
//
// There are the following strategies already implemented,
// * Exact
// * Ordered
// * BitMask
type LevelMatcher interface {
MatchLevel(has, required int64) bool
}
// ExactResourceMatcher matches if both the pattern and resource are exactly equal
type ExactResourceMatcher struct{}
func (*ExactResourceMatcher) MatchResource(pattern, resource string) (bool, error) {
return pattern == resource, nil
}
// RegexResourceMatcher matches if the resource satisfies the pattern (regex)
// It uses go's std regex library which follows the re2 syntax
type RegexResourceMatcher struct {
cache sync.Map
}
func (rm *RegexResourceMatcher) MatchResource(pattern, resource string) (bool, error) {
var expr *regexp.Regexp
v, ok := rm.cache.Load(pattern)
if !ok {
var err error
expr, err = regexp.Compile(pattern)
if err != nil {
return false, err
}
rm.cache.Store(pattern, expr)
} else {
expr = v.(*regexp.Regexp)
}
return expr.MatchString(resource), nil
}
// RegexResourceMatcher matches if the resource has the pattern as prefix
type PrefixResourceMatcher struct{}
func (*PrefixResourceMatcher) MatchResource(prefix, resource string) (bool, error) {
return strings.HasPrefix(resource, prefix), nil
}
// RegexResourceMatcher matches if the resource satisfies the pattern (glob)
// It uses srikrsna/glob package to compile and match globs. It is documented as follows,
//
// Match reports whether resource matches the shell pattern.
// The pattern syntax is:
//
// pattern:
// { term }
// term:
// '*' matches any sequence of non-/ characters
// '**' matches any sequence of characters
// '?' matches any single non-/ character
// '[' [ '!' ] { character-range } ']'
// character class (must be non-empty)
// c matches character c (c != '*', '?', '\\', '[')
// '\\' c matches character c
//
// character-range:
// c matches character c (c != '\\', '-', ']')
// '\\' c matches character c
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of resource, not just a substring.
// The only possible returned error is ErrBadPattern, when pattern
// is malformed.
//
type GlobResourceMatcher struct {
}
func (rm *GlobResourceMatcher) MatchResource(pattern, resource string) (bool, error) {
return glob.Match(pattern, resource)
}
// ExactLevelMatcher matches if both the levels are exactly equal
type ExactLevelMatcher struct {
}
func (*ExactLevelMatcher) MatchLevel(has, needs int) bool {
return has == needs
}
// OrderedLevelMatcher matches if comparision succeeds based on the Asc parameter.
//
// If Asc is false (default), the user needs to have equal or less than the level that is required for an operation i.e. levels behave like ranks
// If Asc is true, the user needs to have equal or greater than the level that is required for an operation
//
// Defaults to Asc false
type OrderedLevelMatcher struct {
Asc bool
}
func (o *OrderedLevelMatcher) MatchLevel(has, needs int64) bool {
return (o.Asc && has >= needs) || (!o.Asc && has <= needs)
}
// BitMaskLevelMatcher matches by doing bitwise AND and checking if the user has all the needed bits set.
type BitMaskLevelMatcher struct {
}
func (*BitMaskLevelMatcher) MatchLevel(has, needs int) bool {
return has&needs == needs
}