char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somrearrange libs into lib and extensions into extsf4a0f5b

main
2.7 KiB89 linesraw
1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::io;
4
5use avril_caps::{Capabilities, env_name};
6
7#[derive(Clone, Default)]
8pub struct Environment {
9    values: BTreeMap<String, (String, String)>,
10}
11
12fn name(value: &str) -> io::Result<Cow<'_, str>> {
13    env_name(value).map_err(|error| io::Error::new(io::ErrorKind::InvalidInput, error))
14}
15
16fn authorize(caps: &Capabilities, name: &str) -> io::Result<()> {
17    caps.check_env(name)
18        .map_err(|error| io::Error::new(io::ErrorKind::PermissionDenied, error))
19}
20
21impl Environment {
22    pub fn new(values: impl IntoIterator<Item = (String, String)>) -> io::Result<Self> {
23        let mut result = Self::default();
24        for (key, value) in values {
25            if value.contains('\0') {
26                return Err(io::Error::new(
27                    io::ErrorKind::InvalidInput,
28                    "Environment values cannot contain NUL",
29                ));
30            }
31            result.values.insert(name(&key)?.into_owned(), (key, value));
32        }
33        Ok(result)
34    }
35
36    pub fn from_process() -> Self {
37        let values = std::env::vars_os().filter_map(|(key, value)| {
38            let key = key.into_string().ok()?;
39            let value = value.into_string().ok()?;
40            Some((name(&key).ok()?.into_owned(), (key, value)))
41        });
42        Self { values: values.collect() }
43    }
44
45    pub fn with_defaults(mut self, defaults: Self) -> Self {
46        for (key, value) in defaults.values {
47            self.values.entry(key).or_insert(value);
48        }
49        self
50    }
51
52    pub fn get(&self, caps: &Capabilities, key: &str) -> io::Result<Option<String>> {
53        let key = name(key)?;
54        authorize(caps, &key)?;
55        Ok(self
56            .values
57            .get(key.as_ref())
58            .map(|(_, value)| value.clone()))
59    }
60
61    pub fn set(&mut self, caps: &Capabilities, key: &str, value: String) -> io::Result<()> {
62        let normalized = name(key)?;
63        if value.contains('\0') {
64            return Err(io::Error::new(
65                io::ErrorKind::InvalidInput,
66                "Environment values cannot contain NUL",
67            ));
68        }
69        authorize(caps, &normalized)?;
70        self.values
71            .insert(normalized.into_owned(), (key.to_owned(), value));
72        Ok(())
73    }
74
75    pub fn delete(&mut self, caps: &Capabilities, key: &str) -> io::Result<()> {
76        let key = name(key)?;
77        authorize(caps, &key)?;
78        self.values.remove(key.as_ref());
79        Ok(())
80    }
81
82    pub fn to_object(&self, caps: &Capabilities) -> Vec<(String, String)> {
83        self.values
84            .iter()
85            .filter(|(key, _)| caps.check_env(key).is_ok())
86            .map(|(_, entry)| entry.clone())
87            .collect()
88    }
89}