canic_core/access/
env.rs

1use crate::{access::AccessError, cdk::api::canister_self, ops::runtime::env::EnvOps};
2use thiserror::Error as ThisError;
3
4///
5/// EnvAccessError
6///
7
8#[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///
27/// Env Checks
28///
29
30#[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
72/// Ensure the caller is the root canister.
73pub(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
85/// Ensure the caller is not the root canister.
86pub(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}