1use alloc::{
2 collections::{btree_map::Entry, BTreeMap},
3 vec::Vec,
4};
5use core::fmt::{self, Display, Formatter};
6
7use rand::{
8 distributions::{Distribution, Standard},
9 Rng,
10};
11use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
12
13use crate::{bytesrepr, Key, URef, URefAddr};
14pub use private::AccessRights;
15
16pub const ACCESS_RIGHTS_SERIALIZED_LENGTH: usize = 1;
18
19#[allow(clippy::bad_bit_mask)]
21mod private {
22 use bitflags::bitflags;
23 #[cfg(feature = "datasize")]
24 use datasize::DataSize;
25
26 bitflags! {
27 #[allow(clippy::derived_hash_with_manual_eq)]
30 #[cfg_attr(feature = "datasize", derive(DataSize))]
31 pub struct AccessRights: u8 {
32 const NONE = 0;
34 const READ = 0b001;
36 const WRITE = 0b010;
38 const ADD = 0b100;
40 const READ_ADD = Self::READ.bits | Self::ADD.bits;
42 const READ_WRITE = Self::READ.bits | Self::WRITE.bits;
44 const ADD_WRITE = Self::ADD.bits | Self::WRITE.bits;
46 const READ_ADD_WRITE = Self::READ.bits | Self::ADD.bits | Self::WRITE.bits;
48 }
49 }
50}
51
52impl Default for AccessRights {
53 fn default() -> Self {
54 AccessRights::NONE
55 }
56}
57
58impl AccessRights {
59 pub fn is_readable(self) -> bool {
61 self & AccessRights::READ == AccessRights::READ
62 }
63
64 pub fn is_writeable(self) -> bool {
66 self & AccessRights::WRITE == AccessRights::WRITE
67 }
68
69 pub fn is_addable(self) -> bool {
71 self & AccessRights::ADD == AccessRights::ADD
72 }
73
74 pub fn is_none(self) -> bool {
76 self == AccessRights::NONE
77 }
78}
79
80impl Display for AccessRights {
81 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
82 match *self {
83 AccessRights::NONE => write!(f, "NONE"),
84 AccessRights::READ => write!(f, "READ"),
85 AccessRights::WRITE => write!(f, "WRITE"),
86 AccessRights::ADD => write!(f, "ADD"),
87 AccessRights::READ_ADD => write!(f, "READ_ADD"),
88 AccessRights::READ_WRITE => write!(f, "READ_WRITE"),
89 AccessRights::ADD_WRITE => write!(f, "ADD_WRITE"),
90 AccessRights::READ_ADD_WRITE => write!(f, "READ_ADD_WRITE"),
91 _ => write!(f, "UNKNOWN"),
92 }
93 }
94}
95
96impl bytesrepr::ToBytes for AccessRights {
97 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
98 self.bits().to_bytes()
99 }
100
101 fn serialized_length(&self) -> usize {
102 ACCESS_RIGHTS_SERIALIZED_LENGTH
103 }
104
105 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
106 writer.push(self.bits());
107 Ok(())
108 }
109}
110
111impl bytesrepr::FromBytes for AccessRights {
112 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
113 let (id, rem) = u8::from_bytes(bytes)?;
114 match AccessRights::from_bits(id) {
115 Some(rights) => Ok((rights, rem)),
116 None => Err(bytesrepr::Error::Formatting),
117 }
118 }
119}
120
121impl Serialize for AccessRights {
122 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
123 self.bits().serialize(serializer)
124 }
125}
126
127impl<'de> Deserialize<'de> for AccessRights {
128 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
129 let bits = u8::deserialize(deserializer)?;
130 AccessRights::from_bits(bits).ok_or_else(|| SerdeError::custom("invalid bits"))
131 }
132}
133
134impl Distribution<AccessRights> for Standard {
135 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AccessRights {
136 let mut result = AccessRights::NONE;
137 if rng.gen() {
138 result |= AccessRights::READ;
139 }
140 if rng.gen() {
141 result |= AccessRights::WRITE;
142 }
143 if rng.gen() {
144 result |= AccessRights::ADD;
145 }
146 result
147 }
148}
149
150#[derive(Debug, PartialEq, Eq)]
152pub enum GrantedAccess {
153 PreExisting,
155 Granted {
157 uref_addr: URefAddr,
159 newly_granted_access_rights: AccessRights,
161 },
162}
163
164#[derive(Debug, PartialEq, Eq)]
166pub struct ContextAccessRights {
167 context_key: Key,
168 access_rights: BTreeMap<URefAddr, AccessRights>,
169}
170
171impl ContextAccessRights {
172 pub fn new<T: IntoIterator<Item = URef>>(context_key: Key, uref_iter: T) -> Self {
175 let mut context_access_rights = ContextAccessRights {
176 context_key,
177 access_rights: BTreeMap::new(),
178 };
179 context_access_rights.do_extend(uref_iter);
180 context_access_rights
181 }
182
183 pub fn context_key(&self) -> Key {
185 self.context_key
186 }
187
188 pub fn extend(&mut self, urefs: &[URef]) {
190 self.do_extend(urefs.iter().copied())
191 }
192
193 fn do_extend<T: IntoIterator<Item = URef>>(&mut self, uref_iter: T) {
195 for uref in uref_iter {
196 match self.access_rights.entry(uref.addr()) {
197 Entry::Occupied(rights) => {
198 *rights.into_mut() = rights.get().union(uref.access_rights());
199 }
200 Entry::Vacant(rights) => {
201 rights.insert(uref.access_rights());
202 }
203 }
204 }
205 }
206
207 pub fn has_access_rights_to_uref(&self, uref: &URef) -> bool {
209 if let Some(known_rights) = self.access_rights.get(&uref.addr()) {
210 let rights_to_check = uref.access_rights();
211 known_rights.contains(rights_to_check)
212 } else {
213 false
215 }
216 }
217
218 pub fn grant_access(&mut self, uref: URef) -> GrantedAccess {
220 match self.access_rights.entry(uref.addr()) {
221 Entry::Occupied(existing_rights) => {
222 let newly_granted_access_rights =
223 uref.access_rights().difference(*existing_rights.get());
224 *existing_rights.into_mut() = existing_rights.get().union(uref.access_rights());
225 if newly_granted_access_rights.is_none() {
226 GrantedAccess::PreExisting
227 } else {
228 GrantedAccess::Granted {
229 uref_addr: uref.addr(),
230 newly_granted_access_rights,
231 }
232 }
233 }
234 Entry::Vacant(rights) => {
235 rights.insert(uref.access_rights());
236 GrantedAccess::Granted {
237 uref_addr: uref.addr(),
238 newly_granted_access_rights: uref.access_rights(),
239 }
240 }
241 }
242 }
243
244 pub fn remove_access(&mut self, uref_addr: URefAddr, access_rights: AccessRights) {
246 if let Some(current_access_rights) = self.access_rights.get_mut(&uref_addr) {
247 current_access_rights.remove(access_rights)
248 }
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255 use crate::UREF_ADDR_LENGTH;
256
257 const UREF_ADDRESS: [u8; UREF_ADDR_LENGTH] = [1; UREF_ADDR_LENGTH];
258 const KEY: Key = Key::URef(URef::new(UREF_ADDRESS, AccessRights::empty()));
259 const UREF_NO_PERMISSIONS: URef = URef::new(UREF_ADDRESS, AccessRights::empty());
260 const UREF_READ: URef = URef::new(UREF_ADDRESS, AccessRights::READ);
261 const UREF_ADD: URef = URef::new(UREF_ADDRESS, AccessRights::ADD);
262 const UREF_WRITE: URef = URef::new(UREF_ADDRESS, AccessRights::WRITE);
263 const UREF_READ_ADD: URef = URef::new(UREF_ADDRESS, AccessRights::READ_ADD);
264 const UREF_READ_ADD_WRITE: URef = URef::new(UREF_ADDRESS, AccessRights::READ_ADD_WRITE);
265
266 fn test_readable(right: AccessRights, is_true: bool) {
267 assert_eq!(right.is_readable(), is_true)
268 }
269
270 #[test]
271 fn test_is_readable() {
272 test_readable(AccessRights::READ, true);
273 test_readable(AccessRights::READ_ADD, true);
274 test_readable(AccessRights::READ_WRITE, true);
275 test_readable(AccessRights::READ_ADD_WRITE, true);
276 test_readable(AccessRights::ADD, false);
277 test_readable(AccessRights::ADD_WRITE, false);
278 test_readable(AccessRights::WRITE, false);
279 }
280
281 fn test_writable(right: AccessRights, is_true: bool) {
282 assert_eq!(right.is_writeable(), is_true)
283 }
284
285 #[test]
286 fn test_is_writable() {
287 test_writable(AccessRights::WRITE, true);
288 test_writable(AccessRights::READ_WRITE, true);
289 test_writable(AccessRights::ADD_WRITE, true);
290 test_writable(AccessRights::READ, false);
291 test_writable(AccessRights::ADD, false);
292 test_writable(AccessRights::READ_ADD, false);
293 test_writable(AccessRights::READ_ADD_WRITE, true);
294 }
295
296 fn test_addable(right: AccessRights, is_true: bool) {
297 assert_eq!(right.is_addable(), is_true)
298 }
299
300 #[test]
301 fn test_is_addable() {
302 test_addable(AccessRights::ADD, true);
303 test_addable(AccessRights::READ_ADD, true);
304 test_addable(AccessRights::READ_WRITE, false);
305 test_addable(AccessRights::ADD_WRITE, true);
306 test_addable(AccessRights::READ, false);
307 test_addable(AccessRights::WRITE, false);
308 test_addable(AccessRights::READ_ADD_WRITE, true);
309 }
310
311 #[test]
312 fn should_check_has_access_rights_to_uref() {
313 let context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
314 assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD));
315 assert!(context_rights.has_access_rights_to_uref(&UREF_READ));
316 assert!(context_rights.has_access_rights_to_uref(&UREF_ADD));
317 assert!(context_rights.has_access_rights_to_uref(&UREF_NO_PERMISSIONS));
318 }
319
320 #[test]
321 fn should_check_does_not_have_access_rights_to_uref() {
322 let context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
323 assert!(!context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
324 assert!(!context_rights
325 .has_access_rights_to_uref(&URef::new([2; UREF_ADDR_LENGTH], AccessRights::empty())));
326 }
327
328 #[test]
329 fn should_extend_access_rights() {
330 let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_NO_PERMISSIONS]);
332 let mut expected_rights = BTreeMap::new();
333 expected_rights.insert(UREF_ADDRESS, AccessRights::empty());
334 assert_eq!(context_rights.access_rights, expected_rights);
335
336 context_rights.extend(&[UREF_READ_ADD]);
338 *expected_rights.get_mut(&UREF_ADDRESS).unwrap() = AccessRights::READ_ADD;
339 assert_eq!(context_rights.access_rights, expected_rights);
340
341 context_rights.extend(&[UREF_READ]);
343 assert_eq!(context_rights.access_rights, expected_rights);
344
345 context_rights.extend(&[UREF_WRITE]);
347 *expected_rights.get_mut(&UREF_ADDRESS).unwrap() = AccessRights::READ_ADD_WRITE;
348 assert_eq!(context_rights.access_rights, expected_rights);
349 }
350
351 #[test]
352 fn should_perform_union_of_access_rights_in_new() {
353 let context_rights =
354 ContextAccessRights::new(KEY, vec![UREF_NO_PERMISSIONS, UREF_READ, UREF_ADD]);
355
356 let mut expected_rights = BTreeMap::new();
358 expected_rights.insert(UREF_ADDRESS, AccessRights::READ_ADD);
359 assert_eq!(context_rights.access_rights, expected_rights);
360 }
361
362 #[test]
363 fn should_grant_access_rights() {
364 let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD]);
365 let granted_access = context_rights.grant_access(UREF_READ);
366 assert_eq!(granted_access, GrantedAccess::PreExisting);
367 let granted_access = context_rights.grant_access(UREF_READ_ADD_WRITE);
368 assert_eq!(
369 granted_access,
370 GrantedAccess::Granted {
371 uref_addr: UREF_ADDRESS,
372 newly_granted_access_rights: AccessRights::WRITE
373 }
374 );
375 assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
376 let new_uref = URef::new([3; 32], AccessRights::all());
377 let granted_access = context_rights.grant_access(new_uref);
378 assert_eq!(
379 granted_access,
380 GrantedAccess::Granted {
381 uref_addr: new_uref.addr(),
382 newly_granted_access_rights: AccessRights::all()
383 }
384 );
385 assert!(context_rights.has_access_rights_to_uref(&new_uref));
386 }
387
388 #[test]
389 fn should_remove_access_rights() {
390 let mut context_rights = ContextAccessRights::new(KEY, vec![UREF_READ_ADD_WRITE]);
391 assert!(context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE));
392
393 context_rights.remove_access(UREF_ADDRESS, AccessRights::WRITE);
395 assert!(
396 !context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE),
397 "Write access should have been removed"
398 );
399
400 context_rights.remove_access(UREF_ADDRESS, AccessRights::WRITE);
402 assert!(
403 !context_rights.has_access_rights_to_uref(&UREF_READ_ADD_WRITE),
404 "Write access should not have been granted back"
405 );
406 assert!(
407 context_rights.has_access_rights_to_uref(&UREF_READ_ADD),
408 "Read and add access should be preserved."
409 );
410
411 context_rights.remove_access(UREF_ADDRESS, AccessRights::READ_ADD);
413 assert!(
414 !context_rights.has_access_rights_to_uref(&UREF_READ_ADD),
415 "Read and add access should have been removed"
416 );
417 assert!(
418 context_rights.has_access_rights_to_uref(&UREF_NO_PERMISSIONS),
419 "The access rights should be empty"
420 );
421 }
422}