1use crate::{access::AccessError, cdk::api::canister_self, ops::runtime::env::EnvOps};
2use thiserror::Error as ThisError;
3
4#[derive(Debug, ThisError)]
9pub enum EnvAccessError {
10 #[error("this endpoint is only available on the prime subnet")]
11 NotPrimeSubnet,
12
13 #[error("this endpoint is only available on prime root")]
14 NotPrimeRoot,
15
16 #[error("operation must be called from the root canister")]
17 NotRoot,
18
19 #[error("operation cannot be called from the root canister")]
20 IsRoot,
21
22 #[error("access dependency unavailable: {0}")]
23 DependencyUnavailable(String),
24}
25
26#[allow(clippy::unused_async)]
31pub async fn is_root() -> Result<(), AccessError> {
32 let root_pid = EnvOps::root_pid()
33 .map_err(|_| EnvAccessError::DependencyUnavailable("root pid unavailable".to_string()))?;
34
35 if root_pid == canister_self() {
36 Ok(())
37 } else {
38 Err(EnvAccessError::NotRoot.into())
39 }
40}
41
42#[allow(clippy::unused_async)]
43pub async fn is_not_root() -> Result<(), AccessError> {
44 let root_pid = EnvOps::root_pid()
45 .map_err(|_| EnvAccessError::DependencyUnavailable("root pid unavailable".to_string()))?;
46
47 if root_pid == canister_self() {
48 Err(EnvAccessError::IsRoot.into())
49 } else {
50 Ok(())
51 }
52}
53
54#[allow(clippy::unused_async)]
55pub async fn is_prime_root() -> Result<(), AccessError> {
56 if EnvOps::is_prime_root() {
57 Ok(())
58 } else {
59 Err(EnvAccessError::NotPrimeRoot.into())
60 }
61}
62
63#[allow(clippy::unused_async)]
64pub async fn is_prime_subnet() -> Result<(), AccessError> {
65 if EnvOps::is_prime_subnet() {
66 Ok(())
67 } else {
68 Err(EnvAccessError::NotPrimeSubnet.into())
69 }
70}
71
72pub(crate) fn require_root() -> Result<(), AccessError> {
74 let root_pid = EnvOps::snapshot()
75 .root_pid
76 .ok_or_else(|| EnvAccessError::DependencyUnavailable("root pid unavailable".to_string()))?;
77
78 if root_pid == canister_self() {
79 Ok(())
80 } else {
81 Err(EnvAccessError::NotRoot.into())
82 }
83}
84
85pub(crate) fn deny_root() -> Result<(), AccessError> {
87 let root_pid = EnvOps::snapshot()
88 .root_pid
89 .ok_or_else(|| EnvAccessError::DependencyUnavailable("root pid unavailable".to_string()))?;
90
91 if root_pid == canister_self() {
92 Err(EnvAccessError::IsRoot.into())
93 } else {
94 Ok(())
95 }
96}