/
CapabilityFilter.cdc
215 lines (188 loc) · 7.5 KB
/
CapabilityFilter.cdc
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/// CapabilityFilter defines `Filter`, an interface to sit on top of a ChildAccount's capabilities. Requested
/// capabilities will only return if the filter's `allowed` method returns true.
///
/// Along with the `Filter` interface are three implementations:
/// - `DenylistFilter` - A filter which contains a mapping of denied Types
/// - `AllowlistFilter` - A filter which contains a mapping of allowed Types
/// - `AllowAllFilter` - A passthrough, all requested capabilities are allowed
///
pub contract CapabilityFilter {
/* --- Canonical Paths --- */
//
pub let StoragePath: StoragePath
pub let PublicPath: PublicPath
pub let PrivatePath: PrivatePath
/* --- Events --- */
//
pub event FilterUpdated(id: UInt64, filterType: Type, type: Type, active: Bool)
/// `Filter` is a simple interface with methods to determine if a Capability is allowed and retrieve details about
/// the Filter itself
///
pub resource interface Filter {
pub fun allowed(cap: Capability): Bool
pub fun getDetails(): AnyStruct
}
/// `DenylistFilter` is a `Filter` which contains a mapping of denied Types
///
pub resource DenylistFilter: Filter {
/// Represents the underlying types which should not ever be returned by a RestrictedChildAccount. The filter
/// will borrow a requested capability, and make sure that the type it gets back is not in the list of denied
/// types
access(self) let deniedTypes: {Type: Bool}
/// Adds a type to the mapping of denied types with a value of true
///
/// @param type: The type to add to the denied types mapping
///
pub fun addType(_ type: Type) {
self.deniedTypes.insert(key: type, true)
emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: true)
}
/// Removes a type from the mapping of denied types
///
/// @param type: The type to remove from the denied types mapping
///
pub fun removeType(_ type: Type) {
if let removed = self.deniedTypes.remove(key: type) {
emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: false)
}
}
/// Removes all types from the mapping of denied types
///
pub fun removeAllTypes() {
for type in self.deniedTypes.keys {
self.removeType(type)
}
}
/// Determines if a requested capability is allowed by this `Filter`
///
/// @param cap: The capability to check
/// @return: true if the capability is allowed, false otherwise
///
pub fun allowed(cap: Capability): Bool {
if let item = cap.borrow<&AnyResource>() {
return !self.deniedTypes.containsKey(item.getType())
}
return false
}
/// Returns details about this filter
///
/// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
/// key as well as types denied indexed on the `deniedTypes` key
///
pub fun getDetails(): AnyStruct {
return {
"type": self.getType(),
"deniedTypes": self.deniedTypes.keys
}
}
init() {
self.deniedTypes = {}
}
}
/// `AllowlistFilter` is a `Filter` which contains a mapping of allowed Types
///
pub resource AllowlistFilter: Filter {
// allowedTypes
// Represents the set of underlying types which are allowed to be
// returned by a RestrictedChildAccount. The filter will borrow
// a requested capability, and make sure that the type it gets back is
// in the list of allowed types
access(self) let allowedTypes: {Type: Bool}
/// Adds a type to the mapping of allowed types with a value of true
///
/// @param type: The type to add to the allowed types mapping
///
pub fun addType(_ type: Type) {
self.allowedTypes.insert(key: type, true)
emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: true)
}
/// Removes a type from the mapping of allowed types
///
/// @param type: The type to remove from the denied types mapping
///
pub fun removeType(_ type: Type) {
if let removed = self.allowedTypes.remove(key: type) {
emit FilterUpdated(id: self.uuid, filterType: self.getType(), type: type, active: false)
}
}
/// Removes all types from the mapping of denied types
///
pub fun removeAllTypes() {
for type in self.allowedTypes.keys {
self.removeType(type)
}
}
/// Determines if a requested capability is allowed by this `Filter`
///
/// @param cap: The capability to check
/// @return: true if the capability is allowed, false otherwise
///
pub fun allowed(cap: Capability): Bool {
if let item = cap.borrow<&AnyResource>() {
return self.allowedTypes.containsKey(item.getType())
}
return false
}
/// Returns details about this filter
///
/// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
/// key as well as types allowed indexed on the `allowedTypes` key
///
pub fun getDetails(): AnyStruct {
return {
"type": self.getType(),
"allowedTypes": self.allowedTypes.keys
}
}
init() {
self.allowedTypes = {}
}
}
/// AllowAllFilter is a passthrough, all requested capabilities are allowed
///
pub resource AllowAllFilter: Filter {
/// Determines if a requested capability is allowed by this `Filter`
///
/// @param cap: The capability to check
/// @return: true since this filter is a passthrough
///
pub fun allowed(cap: Capability): Bool {
return true
}
/// Returns details about this filter
///
/// @return A struct containing details about this filter including this Filter's Type indexed on the `type`
/// key
///
pub fun getDetails(): AnyStruct {
return {
"type": self.getType()
}
}
}
/// Creates a new `Filter` of the given type
///
/// @param t: The type of `Filter` to create
/// @return: A new instance of the given `Filter` type
///
pub fun create(_ t: Type): @AnyResource{Filter} {
post {
result.getType() == t
}
switch t {
case Type<@AllowAllFilter>():
return <- create AllowAllFilter()
case Type<@AllowlistFilter>():
return <- create AllowlistFilter()
case Type<@DenylistFilter>():
return <- create DenylistFilter()
}
panic("unsupported type requested: ".concat(t.identifier))
}
init() {
let identifier = "CapabilityFilter_".concat(self.account.address.toString())
self.StoragePath = StoragePath(identifier: identifier)!
self.PublicPath = PublicPath(identifier: identifier)!
self.PrivatePath = PrivatePath(identifier: identifier)!
}
}