1use crate::{
2 ado_base::permissioning::{Permission, PermissionInfo, PermissioningMessage},
3 amp::{messages::AMPPkt, AndrAddr},
4 common::{context::ExecuteContext, OrderBy},
5 error::ContractError,
6};
7use cosmwasm_std::{ensure, Deps, Env, MessageInfo, Order, Response, Storage};
8use cw_storage_plus::{Bound, Index, IndexList, IndexedMap, MultiIndex};
9
10use super::ADOContract;
11
12const MAX_QUERY_LIMIT: u32 = 50;
13const DEFAULT_QUERY_LIMIT: u32 = 25;
14
15pub struct PermissionsIndices<'a> {
16 pub actor: MultiIndex<'a, String, PermissionInfo, String>,
20 pub action: MultiIndex<'a, String, PermissionInfo, String>,
21}
22
23impl<'a> IndexList<PermissionInfo> for PermissionsIndices<'a> {
24 fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<PermissionInfo>> + '_> {
25 let v: Vec<&dyn Index<PermissionInfo>> = vec![&self.action, &self.actor];
26 Box::new(v.into_iter())
27 }
28}
29
30pub fn permissions<'a>() -> IndexedMap<'a, &'a str, PermissionInfo, PermissionsIndices<'a>> {
34 let indexes = PermissionsIndices {
35 actor: MultiIndex::new(|_pk: &[u8], r| r.actor.clone(), "andr_permissions", "actor"),
36 action: MultiIndex::new(
37 |_pk: &[u8], r| r.action.clone(),
38 "andr_permissions",
39 "action",
40 ),
41 };
42 IndexedMap::new("andr_permissions", indexes)
43}
44
45impl<'a> ADOContract<'a> {
46 pub fn execute_permissioning(
47 &self,
48 ctx: ExecuteContext,
49 msg: PermissioningMessage,
50 ) -> Result<Response, ContractError> {
51 match msg {
52 PermissioningMessage::SetPermission {
53 actor,
54 action,
55 permission,
56 } => self.execute_set_permission(ctx, actor, action, permission),
57 PermissioningMessage::RemovePermission { action, actor } => {
58 self.execute_remove_permission(ctx, actor, action)
59 }
60 PermissioningMessage::PermissionAction { action } => {
61 self.execute_permission_action(ctx, action)
62 }
63 PermissioningMessage::DisableActionPermissioning { action } => {
64 self.execute_disable_action_permission(ctx, action)
65 }
66 }
67 }
68 pub fn is_permissioned(
72 &self,
73 store: &mut dyn Storage,
74 env: Env,
75 action: impl Into<String>,
76 actor: impl Into<String>,
77 ) -> Result<(), ContractError> {
78 let action_string: String = action.into();
80 let actor_string: String = actor.into();
81
82 if self.is_contract_owner(store, actor_string.as_str())? {
83 return Ok(());
84 }
85
86 let permission = Self::get_permission(store, action_string.clone(), actor_string.clone())?;
87 let permissioned_action = self
88 .permissioned_actions
89 .may_load(store, action_string.clone())?
90 .unwrap_or(false);
91 match permission {
92 Some(mut permission) => {
93 ensure!(
94 permission.is_permissioned(&env, permissioned_action),
95 ContractError::Unauthorized {}
96 );
97
98 if let Permission::Limited { .. } = permission {
100 permission.consume_use()?;
101 permissions().save(
102 store,
103 (action_string.clone() + actor_string.as_str()).as_str(),
104 &PermissionInfo {
105 action: action_string,
106 actor: actor_string,
107 permission,
108 },
109 )?;
110 }
111
112 Ok(())
113 }
114 None => {
115 ensure!(!permissioned_action, ContractError::Unauthorized {});
116 Ok(())
117 }
118 }
119 }
120
121 pub fn is_permissioned_strict(
127 &self,
128 store: &mut dyn Storage,
129 env: Env,
130 action: impl Into<String>,
131 actor: impl Into<String>,
132 ) -> Result<(), ContractError> {
133 let action_string: String = action.into();
135 let actor_string: String = actor.into();
136
137 if self.is_contract_owner(store, actor_string.as_str())? {
138 return Ok(());
139 }
140
141 let permission = Self::get_permission(store, action_string.clone(), actor_string.clone())?;
142 match permission {
143 Some(mut permission) => {
144 ensure!(
145 permission.is_permissioned(&env, true),
146 ContractError::Unauthorized {}
147 );
148
149 if let Permission::Limited { .. } = permission {
151 permission.consume_use()?;
152 permissions().save(
153 store,
154 (action_string.clone() + actor_string.as_str()).as_str(),
155 &PermissionInfo {
156 action: action_string,
157 actor: actor_string,
158 permission,
159 },
160 )?;
161 }
162
163 Ok(())
164 }
165 None => Err(ContractError::Unauthorized {}),
166 }
167 }
168
169 pub fn get_permission(
171 store: &dyn Storage,
172 action: impl Into<String>,
173 actor: impl Into<String>,
174 ) -> Result<Option<Permission>, ContractError> {
175 let action = action.into();
176 let actor = actor.into();
177 let key = action + &actor;
178 if let Some(PermissionInfo { permission, .. }) = permissions().may_load(store, &key)? {
179 Ok(Some(permission))
180 } else {
181 Ok(None)
182 }
183 }
184
185 pub fn set_permission(
187 store: &mut dyn Storage,
188 action: impl Into<String>,
189 actor: impl Into<String>,
190 permission: Permission,
191 ) -> Result<(), ContractError> {
192 let action = action.into();
193 let actor = actor.into();
194 let key = action.clone() + &actor;
195 permissions().save(
196 store,
197 &key,
198 &PermissionInfo {
199 action,
200 actor,
201 permission,
202 },
203 )?;
204 Ok(())
205 }
206
207 pub fn remove_permission(
209 store: &mut dyn Storage,
210 action: impl Into<String>,
211 actor: impl Into<String>,
212 ) -> Result<(), ContractError> {
213 let action = action.into();
214 let actor = actor.into();
215 let key = action + &actor;
216 permissions().remove(store, &key)?;
217 Ok(())
218 }
219
220 pub fn execute_set_permission(
225 &self,
226 ctx: ExecuteContext,
227 actor: AndrAddr,
228 action: impl Into<String>,
229 permission: Permission,
230 ) -> Result<Response, ContractError> {
231 ensure!(
232 Self::is_contract_owner(self, ctx.deps.storage, ctx.info.sender.as_str())?,
233 ContractError::Unauthorized {}
234 );
235 let actor_addr = actor.get_raw_address(&ctx.deps.as_ref())?;
236 let action = action.into();
237 Self::set_permission(
238 ctx.deps.storage,
239 action.clone(),
240 actor_addr.clone(),
241 permission.clone(),
242 )?;
243
244 Ok(Response::default().add_attributes(vec![
245 ("action", "set_permission"),
246 ("actor", actor_addr.as_str()),
247 ("action", action.as_str()),
248 ("permission", permission.to_string().as_str()),
249 ]))
250 }
251
252 pub fn execute_remove_permission(
254 &self,
255 ctx: ExecuteContext,
256 actor: AndrAddr,
257 action: impl Into<String>,
258 ) -> Result<Response, ContractError> {
259 ensure!(
260 Self::is_contract_owner(self, ctx.deps.storage, ctx.info.sender.as_str())?,
261 ContractError::Unauthorized {}
262 );
263 let actor_addr = actor.get_raw_address(&ctx.deps.as_ref())?;
264 let action = action.into();
265 Self::remove_permission(ctx.deps.storage, action.clone(), actor_addr.clone())?;
266
267 Ok(Response::default().add_attributes(vec![
268 ("action", "remove_permission"),
269 ("actor", actor_addr.as_str()),
270 ("action", action.as_str()),
271 ]))
272 }
273
274 pub fn permission_action(
276 &self,
277 action: impl Into<String>,
278 store: &mut dyn Storage,
279 ) -> Result<(), ContractError> {
280 self.permissioned_actions
281 .save(store, action.into(), &true)?;
282 Ok(())
283 }
284
285 pub fn disable_action_permission(&self, action: impl Into<String>, store: &mut dyn Storage) {
287 self.permissioned_actions.remove(store, action.into());
288 }
289
290 pub fn execute_permission_action(
291 &self,
292 ctx: ExecuteContext,
293 action: impl Into<String>,
294 ) -> Result<Response, ContractError> {
295 let action_string: String = action.into();
296 ensure!(
297 Self::is_contract_owner(self, ctx.deps.storage, ctx.info.sender.as_str())?,
298 ContractError::Unauthorized {}
299 );
300 self.permission_action(action_string.clone(), ctx.deps.storage)?;
301 Ok(Response::default().add_attributes(vec![
302 ("action", "permission_action"),
303 ("action", action_string.as_str()),
304 ]))
305 }
306
307 pub fn execute_disable_action_permission(
308 &self,
309 ctx: ExecuteContext,
310 action: impl Into<String>,
311 ) -> Result<Response, ContractError> {
312 let action_string: String = action.into();
313 ensure!(
314 Self::is_contract_owner(self, ctx.deps.storage, ctx.info.sender.as_str())?,
315 ContractError::Unauthorized {}
316 );
317 Self::disable_action_permission(self, action_string.clone(), ctx.deps.storage);
318 Ok(Response::default().add_attributes(vec![
319 ("action", "disable_action_permission"),
320 ("action", action_string.as_str()),
321 ]))
322 }
323
324 pub fn query_permissions(
326 &self,
327 deps: Deps,
328 actor: impl Into<String>,
329 limit: Option<u32>,
330 start_after: Option<String>,
331 ) -> Result<Vec<PermissionInfo>, ContractError> {
332 let actor = actor.into();
333 let min = start_after.map(Bound::inclusive);
334 let limit = limit.unwrap_or(DEFAULT_QUERY_LIMIT).min(MAX_QUERY_LIMIT) as usize;
335 let permissions = permissions()
336 .idx
337 .actor
338 .prefix(actor)
339 .range(deps.storage, min, None, Order::Ascending)
340 .take(limit)
341 .map(|p| p.unwrap().1)
342 .collect::<Vec<PermissionInfo>>();
343 Ok(permissions)
344 }
345
346 pub fn query_permissioned_actions(&self, deps: Deps) -> Result<Vec<String>, ContractError> {
347 let actions = self
348 .permissioned_actions
349 .keys(deps.storage, None, None, Order::Ascending)
350 .map(|p| p.unwrap())
351 .collect::<Vec<String>>();
352 Ok(actions)
353 }
354
355 pub fn query_permissioned_actors(
356 &self,
357 deps: Deps,
358 action: impl Into<String>,
359 start_after: Option<String>,
360 limit: Option<u32>,
361 order_by: Option<OrderBy>,
362 ) -> Result<Vec<String>, ContractError> {
363 let action_string: String = action.into();
364 let order_by = match order_by {
365 Some(OrderBy::Desc) => Order::Descending,
366 _ => Order::Ascending,
367 };
368
369 let actors = permissions()
370 .idx
371 .action
372 .prefix(action_string.clone())
373 .keys(
374 deps.storage,
375 start_after.map(Bound::inclusive),
376 None,
377 order_by,
378 )
379 .take((limit).unwrap_or(DEFAULT_QUERY_LIMIT).min(MAX_QUERY_LIMIT) as usize)
380 .map(|p| {
381 p.unwrap()
382 .strip_prefix(action_string.as_str())
383 .unwrap()
384 .to_string()
385 })
386 .collect::<Vec<String>>();
387
388 Ok(actors)
389 }
390}
391
392pub fn is_context_permissioned(
398 storage: &mut dyn Storage,
399 info: &MessageInfo,
400 env: &Env,
401 ctx: &Option<AMPPkt>,
402 action: impl Into<String>,
403) -> Result<bool, ContractError> {
404 let contract = ADOContract::default();
405
406 match ctx {
407 Some(amp_ctx) => {
408 let action: String = action.into();
409 let is_origin_permissioned = contract.is_permissioned(
410 storage,
411 env.clone(),
412 action.clone(),
413 amp_ctx.ctx.get_origin().as_str(),
414 );
415 let is_previous_sender_permissioned = contract.is_permissioned(
416 storage,
417 env.clone(),
418 action,
419 amp_ctx.ctx.get_previous_sender().as_str(),
420 );
421 Ok(is_origin_permissioned.is_ok() || is_previous_sender_permissioned.is_ok())
422 }
423 None => Ok(contract
424 .is_permissioned(storage, env.clone(), action, info.sender.to_string())
425 .is_ok()),
426 }
427}
428
429pub fn is_context_permissioned_strict(
435 storage: &mut dyn Storage,
436 info: &MessageInfo,
437 env: &Env,
438 ctx: &Option<AMPPkt>,
439 action: impl Into<String>,
440) -> Result<bool, ContractError> {
441 let contract = ADOContract::default();
442
443 match ctx {
444 Some(amp_ctx) => {
445 let action: String = action.into();
446 let is_origin_permissioned = contract.is_permissioned_strict(
447 storage,
448 env.clone(),
449 action.clone(),
450 amp_ctx.ctx.get_origin().as_str(),
451 );
452 let is_previous_sender_permissioned = contract.is_permissioned_strict(
453 storage,
454 env.clone(),
455 action,
456 amp_ctx.ctx.get_previous_sender().as_str(),
457 );
458 Ok(is_origin_permissioned.is_ok() || is_previous_sender_permissioned.is_ok())
459 }
460 None => Ok(contract
461 .is_permissioned_strict(storage, env.clone(), action, info.sender.to_string())
462 .is_ok()),
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use cosmwasm_std::{
469 testing::{mock_dependencies, mock_env, mock_info},
470 Addr,
471 };
472
473 use crate::{ado_base::AndromedaMsg, amp::messages::AMPPkt, common::MillisecondsExpiration};
474
475 use super::*;
476
477 #[test]
478 fn test_permissioned_action() {
479 let mut deps = mock_dependencies();
480 let env = mock_env();
481 let action = "action";
482 let actor = "actor";
483 let contract = ADOContract::default();
484 contract
485 .owner
486 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
487 .unwrap();
488
489 ADOContract::default()
490 .permission_action(action, deps.as_mut().storage)
491 .unwrap();
492
493 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
495
496 assert!(res.is_err());
497 let permission = Permission::whitelisted(None);
498 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
499
500 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
501
502 assert!(res.is_ok());
503
504 ADOContract::remove_permission(deps.as_mut().storage, action, actor).unwrap();
505
506 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
508
509 assert!(res.is_err());
510 let permission = Permission::limited(None, 1);
511 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
512
513 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
514
515 assert!(res.is_ok());
516
517 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
519 assert!(res.is_err());
520
521 ADOContract::remove_permission(deps.as_mut().storage, action, actor).unwrap();
522
523 let permission = Permission::blacklisted(None);
525 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
526
527 let res = contract.is_permissioned(deps.as_mut().storage, env, action, actor);
528
529 assert!(res.is_err());
530 }
531
532 #[test]
533 fn test_unpermissioned_action_blacklisted() {
534 let mut deps = mock_dependencies();
535 let env = mock_env();
536 let action = "action";
537 let actor = "actor";
538 let contract = ADOContract::default();
539 contract
540 .owner
541 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
542 .unwrap();
543
544 ADOContract::default()
545 .permission_action(action, deps.as_mut().storage)
546 .unwrap();
547
548 let permission = Permission::blacklisted(None);
550 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
551
552 let res = contract.is_permissioned(deps.as_mut().storage, env, action, actor);
553
554 assert!(res.is_err());
555 }
556
557 #[test]
558 fn test_strict_permissioning() {
559 let mut deps = mock_dependencies();
560 let env = mock_env();
561 let action = "action";
562 let actor = "actor";
563 let contract = ADOContract::default();
564 contract
565 .owner
566 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
567 .unwrap();
568
569 let res =
570 contract.is_permissioned_strict(deps.as_mut().storage, env.clone(), action, actor);
571 assert!(res.is_err());
572
573 let permission = Permission::whitelisted(None);
574 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
575
576 let res = contract.is_permissioned_strict(deps.as_mut().storage, env, action, actor);
577 assert!(res.is_ok());
578 }
579
580 #[test]
581 fn test_owner_escape_clause() {
582 let mut deps = mock_dependencies();
583 let env = mock_env();
584 let action = "action";
585 let actor = "actor";
586 let contract = ADOContract::default();
587 contract
588 .owner
589 .save(deps.as_mut().storage, &Addr::unchecked(actor))
590 .unwrap();
591
592 let res =
593 contract.is_permissioned_strict(deps.as_mut().storage, env.clone(), action, actor);
594 assert!(res.is_ok());
595
596 let res = contract.is_permissioned(deps.as_mut().storage, env, action, actor);
597 assert!(res.is_ok());
598 }
599
600 #[test]
601 fn test_set_permission_unauthorized() {
602 let mut deps = mock_dependencies();
603 let env = mock_env();
604 let contract = ADOContract::default();
605 contract
606 .owner
607 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
608 .unwrap();
609 let msg = AndromedaMsg::Permissioning(PermissioningMessage::SetPermission {
610 actor: AndrAddr::from_string("actor"),
611 action: "action".to_string(),
612 permission: Permission::Whitelisted(None),
613 });
614 let ctx = ExecuteContext::new(deps.as_mut(), mock_info("attacker", &[]), env);
615 let res = contract.execute(ctx, msg);
616
617 assert!(res.is_err());
618 assert_eq!(res.unwrap_err(), ContractError::Unauthorized {});
619 }
620
621 #[test]
622 fn test_permission_action_unauthorized() {
623 let mut deps = mock_dependencies();
624 let env = mock_env();
625 let contract = ADOContract::default();
626 contract
627 .owner
628 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
629 .unwrap();
630 let msg = AndromedaMsg::Permissioning(PermissioningMessage::PermissionAction {
631 action: "action".to_string(),
632 });
633 let ctx = ExecuteContext::new(deps.as_mut(), mock_info("attacker", &[]), env);
634 let res = contract.execute(ctx, msg);
635
636 assert!(res.is_err());
637 assert_eq!(res.unwrap_err(), ContractError::Unauthorized {});
638 }
639
640 #[test]
641 fn test_disable_permissioning_unauthorized() {
642 let mut deps = mock_dependencies();
643 let env = mock_env();
644 let contract = ADOContract::default();
645 contract
646 .owner
647 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
648 .unwrap();
649 let msg = AndromedaMsg::Permissioning(PermissioningMessage::DisableActionPermissioning {
650 action: "action".to_string(),
651 });
652 let ctx = ExecuteContext::new(deps.as_mut(), mock_info("attacker", &[]), env);
653 let res = contract.execute(ctx, msg);
654
655 assert!(res.is_err());
656 assert_eq!(res.unwrap_err(), ContractError::Unauthorized {});
657 }
658
659 #[test]
660 fn test_remove_permission_unauthorized() {
661 let mut deps = mock_dependencies();
662 let env = mock_env();
663 let contract = ADOContract::default();
664 contract
665 .owner
666 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
667 .unwrap();
668 let msg = AndromedaMsg::Permissioning(PermissioningMessage::RemovePermission {
669 action: "action".to_string(),
670 actor: AndrAddr::from_string("actor"),
671 });
672 let ctx = ExecuteContext::new(deps.as_mut(), mock_info("attacker", &[]), env);
673 let res = contract.execute(ctx, msg);
674
675 assert!(res.is_err());
676 assert_eq!(res.unwrap_err(), ContractError::Unauthorized {});
677 }
678
679 #[test]
680 fn test_permission_expiration() {
681 let mut deps = mock_dependencies();
682 let mut env = mock_env();
683 env.block.height = 0;
684 let action = "action";
685 let actor = "actor";
686 let contract = ADOContract::default();
687 let time = 2;
688 let expiration = MillisecondsExpiration::from_seconds(time);
689
690 env.block.time = MillisecondsExpiration::from_seconds(0).into();
691 contract
692 .owner
693 .save(deps.as_mut().storage, &Addr::unchecked("owner"))
694 .unwrap();
695
696 ADOContract::default()
697 .permission_action(action, deps.as_mut().storage)
698 .unwrap();
699
700 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
701
702 assert!(res.is_err());
703
704 let permission = Permission::Whitelisted(Some(expiration));
706 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
707
708 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
709 assert!(res.is_ok());
710
711 env.block.time = MillisecondsExpiration::from_seconds(time + 1).into();
712
713 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
714 assert!(res.is_err());
715
716 env.block.time = MillisecondsExpiration::from_seconds(0).into();
717 let permission = Permission::Blacklisted(Some(expiration));
719 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission).unwrap();
720
721 let res = contract.is_permissioned(deps.as_mut().storage, env.clone(), action, actor);
722 assert!(res.is_err());
723
724 env.block.time = MillisecondsExpiration::from_seconds(time + 1).into();
725
726 let res = contract.is_permissioned(deps.as_mut().storage, env, action, actor);
727 assert!(res.is_ok());
728 }
729
730 #[test]
731 fn test_context_permissions() {
732 let mut deps = mock_dependencies();
733 let env = mock_env();
734 let actor = "actor";
735 let info = mock_info(actor, &[]);
736 let action = "action";
737
738 let context = ExecuteContext::new(deps.as_mut(), info.clone(), env.clone());
739 let contract = ADOContract::default();
740
741 contract
742 .owner
743 .save(context.deps.storage, &Addr::unchecked("owner"))
744 .unwrap();
745
746 assert!(is_context_permissioned(
747 context.deps.storage,
748 &context.info,
749 &context.env,
750 &context.amp_ctx,
751 action
752 )
753 .unwrap());
754
755 let context = ExecuteContext::new(deps.as_mut(), info.clone(), env.clone());
756 ADOContract::default()
757 .permission_action(action, context.deps.storage)
758 .unwrap();
759
760 assert!(!is_context_permissioned(
761 context.deps.storage,
762 &context.info,
763 &context.env,
764 &context.amp_ctx,
765 action
766 )
767 .unwrap());
768
769 let context = ExecuteContext::new(deps.as_mut(), info, env.clone());
770 let permission = Permission::whitelisted(None);
771 ADOContract::set_permission(context.deps.storage, action, actor, permission).unwrap();
772
773 assert!(is_context_permissioned(
774 context.deps.storage,
775 &context.info,
776 &context.env,
777 &context.amp_ctx,
778 action
779 )
780 .unwrap());
781
782 let unauth_info = mock_info("mock_actor", &[]);
783 let context = ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone());
784
785 assert!(!is_context_permissioned(
786 context.deps.storage,
787 &context.info,
788 &context.env,
789 &context.amp_ctx,
790 action
791 )
792 .unwrap());
793
794 let amp_ctx = AMPPkt::new("mock_actor", actor, vec![]);
795 let context =
796 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
797
798 assert!(is_context_permissioned(
799 context.deps.storage,
800 &context.info,
801 &context.env,
802 &context.amp_ctx,
803 action
804 )
805 .unwrap());
806
807 let amp_ctx = AMPPkt::new(actor, "mock_actor", vec![]);
808 let context =
809 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
810
811 assert!(is_context_permissioned(
812 context.deps.storage,
813 &context.info,
814 &context.env,
815 &context.amp_ctx,
816 action
817 )
818 .unwrap());
819
820 let amp_ctx = AMPPkt::new("mock_actor", "mock_actor", vec![]);
821 let context =
822 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
823
824 assert!(!is_context_permissioned(
825 context.deps.storage,
826 &context.info,
827 &context.env,
828 &context.amp_ctx,
829 action
830 )
831 .unwrap());
832
833 let amp_ctx = AMPPkt::new("owner", "mock_actor", vec![]);
834 let context =
835 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
836
837 assert!(is_context_permissioned(
838 context.deps.storage,
839 &context.info,
840 &context.env,
841 &context.amp_ctx,
842 action
843 )
844 .unwrap());
845
846 let amp_ctx = AMPPkt::new("mock_actor", "owner", vec![]);
847 let context = ExecuteContext::new(deps.as_mut(), unauth_info, env).with_ctx(amp_ctx);
848
849 assert!(is_context_permissioned(
850 context.deps.storage,
851 &context.info,
852 &context.env,
853 &context.amp_ctx,
854 action
855 )
856 .unwrap());
857 }
858
859 #[test]
860 fn test_context_permissions_strict() {
861 let mut deps = mock_dependencies();
862 let env = mock_env();
863 let actor = "actor";
864 let info = mock_info(actor, &[]);
865 let action = "action";
866
867 let context = ExecuteContext::new(deps.as_mut(), info.clone(), env.clone());
868 let contract = ADOContract::default();
869
870 contract
871 .owner
872 .save(context.deps.storage, &Addr::unchecked("owner"))
873 .unwrap();
874
875 assert!(!is_context_permissioned_strict(
876 context.deps.storage,
877 &context.info,
878 &context.env,
879 &context.amp_ctx,
880 action
881 )
882 .unwrap());
883
884 let context = ExecuteContext::new(deps.as_mut(), info, env.clone());
885 let permission = Permission::whitelisted(None);
886 ADOContract::set_permission(context.deps.storage, action, actor, permission).unwrap();
887
888 assert!(is_context_permissioned_strict(
889 context.deps.storage,
890 &context.info,
891 &context.env,
892 &context.amp_ctx,
893 action
894 )
895 .unwrap());
896
897 let unauth_info = mock_info("mock_actor", &[]);
898 let context = ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone());
899
900 assert!(!is_context_permissioned_strict(
901 context.deps.storage,
902 &context.info,
903 &context.env,
904 &context.amp_ctx,
905 action
906 )
907 .unwrap());
908
909 let amp_ctx = AMPPkt::new("mock_actor", actor, vec![]);
910 let context =
911 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
912
913 assert!(is_context_permissioned_strict(
914 context.deps.storage,
915 &context.info,
916 &context.env,
917 &context.amp_ctx,
918 action
919 )
920 .unwrap());
921
922 let amp_ctx = AMPPkt::new(actor, "mock_actor", vec![]);
923 let context =
924 ExecuteContext::new(deps.as_mut(), unauth_info.clone(), env.clone()).with_ctx(amp_ctx);
925
926 assert!(is_context_permissioned_strict(
927 context.deps.storage,
928 &context.info,
929 &context.env,
930 &context.amp_ctx,
931 action
932 )
933 .unwrap());
934
935 let amp_ctx = AMPPkt::new("mock_actor", "mock_actor", vec![]);
936 let context = ExecuteContext::new(deps.as_mut(), unauth_info, env).with_ctx(amp_ctx);
937
938 assert!(!is_context_permissioned_strict(
939 context.deps.storage,
940 &context.info,
941 &context.env,
942 &context.amp_ctx,
943 action
944 )
945 .unwrap());
946 }
947
948 #[test]
949 fn test_query_permissions() {
950 let actor = "actor";
951 let mut deps = mock_dependencies();
952
953 let permissions = ADOContract::default()
954 .query_permissions(deps.as_ref(), actor, None, None)
955 .unwrap();
956
957 assert!(permissions.is_empty());
958
959 let permission = Permission::whitelisted(None);
960 let action = "action";
961
962 ADOContract::set_permission(deps.as_mut().storage, action, actor, permission.clone())
963 .unwrap();
964
965 let permissions = ADOContract::default()
966 .query_permissions(deps.as_ref(), actor, None, None)
967 .unwrap();
968
969 assert_eq!(permissions.len(), 1);
970 assert_eq!(permissions[0].action, action);
971 assert_eq!(permissions[0].permission, permission);
972
973 let multi_permissions = vec![
974 ("action2".to_string(), Permission::blacklisted(None)),
975 ("action3".to_string(), Permission::whitelisted(None)),
976 ("action4".to_string(), Permission::blacklisted(None)),
977 ("action5".to_string(), Permission::whitelisted(None)),
978 ];
979
980 for (action, permission) in multi_permissions {
981 ADOContract::set_permission(deps.as_mut().storage, &action, actor, permission).unwrap();
982 }
983
984 let permissions = ADOContract::default()
985 .query_permissions(deps.as_ref(), actor, None, None)
986 .unwrap();
987
988 assert_eq!(permissions.len(), 5);
989 }
990
991 #[test]
992 fn test_query_permissioned_actions() {
993 let mut deps = mock_dependencies();
994 let env = mock_env();
995 let info = mock_info("owner", &[]);
996 let ctx = ExecuteContext {
997 deps: deps.as_mut(),
998 env,
999 info: info.clone(),
1000 amp_ctx: None,
1001 };
1002
1003 let contract = ADOContract::default();
1004
1005 contract.owner.save(ctx.deps.storage, &info.sender).unwrap();
1006
1007 let actions = ADOContract::default()
1008 .query_permissioned_actions(ctx.deps.as_ref())
1009 .unwrap();
1010
1011 assert!(actions.is_empty());
1012
1013 ADOContract::default()
1014 .execute_permission_action(ctx, "action")
1015 .unwrap();
1016
1017 let actions = ADOContract::default()
1018 .query_permissioned_actions(deps.as_ref())
1019 .unwrap();
1020
1021 assert_eq!(actions.len(), 1);
1022 assert_eq!(actions[0], "action");
1023 }
1024
1025 #[test]
1026 fn test_query_permissioned_actors() {
1027 let mut deps = mock_dependencies();
1028 let env = mock_env();
1029 let info = mock_info("owner", &[]);
1030 let ctx = ExecuteContext {
1031 deps: deps.as_mut(),
1032 env,
1033 info: info.clone(),
1034 amp_ctx: None,
1035 };
1036
1037 let contract = ADOContract::default();
1038
1039 contract.owner.save(ctx.deps.storage, &info.sender).unwrap();
1040
1041 let actor = "actor";
1042 let action = "action";
1043 ADOContract::default()
1044 .execute_permission_action(ctx, action)
1045 .unwrap();
1046
1047 ADOContract::set_permission(deps.as_mut().storage, action, actor, Permission::default())
1048 .unwrap();
1049 let actors = ADOContract::default()
1050 .query_permissioned_actors(deps.as_ref(), action, None, None, None)
1051 .unwrap();
1052
1053 assert_eq!(actors.len(), 1);
1054 assert_eq!(actors[0], actor);
1055 }
1056}