rhai_process/
config.rs

1use crate::util::runtime_error;
2use crate::RhaiResult;
3use std::collections::HashSet;
4
5#[derive(Clone, Debug)]
6pub struct Config {
7    pub(crate) command_policy: ListPolicy,
8    pub(crate) env_policy: ListPolicy,
9    pub(crate) default_timeout_ms: Option<u64>,
10}
11
12impl Default for Config {
13    fn default() -> Self {
14        Self {
15            command_policy: ListPolicy::Unrestricted,
16            env_policy: ListPolicy::Unrestricted,
17            default_timeout_ms: None,
18        }
19    }
20}
21
22impl Config {
23    pub fn allow_commands<I, S>(mut self, commands: I) -> Self
24    where
25        I: IntoIterator<Item = S>,
26        S: Into<String>,
27    {
28        self.command_policy
29            .insert_allow(commands.into_iter().map(Into::into));
30        self
31    }
32
33    pub fn deny_commands<I, S>(mut self, commands: I) -> Self
34    where
35        I: IntoIterator<Item = S>,
36        S: Into<String>,
37    {
38        self.command_policy
39            .insert_deny(commands.into_iter().map(Into::into));
40        self
41    }
42
43    pub fn allow_env_vars<I, S>(mut self, keys: I) -> Self
44    where
45        I: IntoIterator<Item = S>,
46        S: Into<String>,
47    {
48        self.env_policy
49            .insert_allow(keys.into_iter().map(Into::into));
50        self
51    }
52
53    pub fn deny_env_vars<I, S>(mut self, keys: I) -> Self
54    where
55        I: IntoIterator<Item = S>,
56        S: Into<String>,
57    {
58        self.env_policy
59            .insert_deny(keys.into_iter().map(Into::into));
60        self
61    }
62
63    pub fn default_timeout_ms(mut self, timeout: u64) -> Self {
64        if timeout == 0 {
65            panic!("default_timeout_ms must be greater than zero");
66        }
67        self.default_timeout_ms = Some(timeout);
68        self
69    }
70
71    pub(crate) fn ensure_command_allowed(&self, name: &str) -> RhaiResult<()> {
72        if self.command_policy.is_allowed(name) {
73            Ok(())
74        } else {
75            Err(runtime_error(format!("command '{name}' is not permitted")))
76        }
77    }
78
79    pub(crate) fn ensure_env_allowed(&self, key: &str) -> RhaiResult<()> {
80        if self.env_policy.is_allowed(key) {
81            Ok(())
82        } else {
83            Err(runtime_error(format!(
84                "environment variable '{key}' is not permitted"
85            )))
86        }
87    }
88}
89
90#[derive(Clone, Debug)]
91pub(crate) enum ListPolicy {
92    Unrestricted,
93    Allow(HashSet<String>),
94    Deny(HashSet<String>),
95}
96
97impl ListPolicy {
98    fn insert_allow<I>(&mut self, values: I)
99    where
100        I: IntoIterator<Item = String>,
101    {
102        match self {
103            ListPolicy::Unrestricted => {
104                let mut set = HashSet::new();
105                set.extend(values);
106                *self = ListPolicy::Allow(set);
107            }
108            ListPolicy::Allow(existing) => existing.extend(values),
109            ListPolicy::Deny(_) => {
110                panic!("deny list already specified; allow list cannot be combined")
111            }
112        }
113    }
114
115    fn insert_deny<I>(&mut self, values: I)
116    where
117        I: IntoIterator<Item = String>,
118    {
119        match self {
120            ListPolicy::Unrestricted => {
121                let mut set = HashSet::new();
122                set.extend(values);
123                *self = ListPolicy::Deny(set);
124            }
125            ListPolicy::Deny(existing) => existing.extend(values),
126            ListPolicy::Allow(_) => {
127                panic!("allow list already specified; deny list cannot be combined")
128            }
129        }
130    }
131
132    fn is_allowed(&self, value: &str) -> bool {
133        match self {
134            ListPolicy::Unrestricted => true,
135            ListPolicy::Allow(list) => list.contains(value),
136            ListPolicy::Deny(list) => !list.contains(value),
137        }
138    }
139}