cyfs_base/objects/object_map/
access.rs

1use crate::*;
2
3use std::borrow::Cow;
4
5pub struct OpEnvPathAccess {
6    limit_path: String,
7    access: AccessPermissions,
8}
9
10impl OpEnvPathAccess {
11    pub fn new(path: &str, access: AccessPermissions) -> Self {
12        let limit_path = Self::fix_path(path).into_owned();
13
14        Self { limit_path, access }
15    }
16
17    // 以/开头,并以/结尾
18    fn fix_path(path: &str) -> Cow<str> {
19        if path.starts_with('/') {
20            if path.ends_with('/') {
21                Cow::Borrowed(path)
22            } else {
23                Cow::Owned(format!("{}/", path))
24            }
25        } else {
26            if path.ends_with('/') {
27                Cow::Owned(format!("/{}", path))
28            } else {
29                Cow::Owned(format!("/{}/", path))
30            }
31        }
32    }
33
34    pub fn check_full_path(&self, full_path: &str, op_type: RequestOpType) -> BuckyResult<()> {
35        let full_path = Self::fix_path(full_path);
36        assert!(full_path.starts_with('/'));
37
38        if full_path.starts_with(self.limit_path.as_str()) {
39            if self.access.test_op(op_type) {
40                Ok(())
41            } else {
42                let msg = format!("op is not allowed within path limiter! path={}, limiter={}, access={}, op='{:?}'", 
43                            full_path, self.limit_path, self.access.as_str(), op_type);
44                error!("{}", msg);
45                Err(BuckyError::new(BuckyErrorCode::PermissionDenied, msg))
46            }
47        } else {
48            let msg = format!(
49                "full path is out of path limiter! path={}, limiter={}",
50                full_path, self.limit_path
51            );
52            error!("{}", msg);
53            Err(BuckyError::new(BuckyErrorCode::PermissionDenied, msg))
54        }
55    }
56
57    pub fn check_full_path_list(
58        &self,
59        list: &Vec<String>,
60        op_type: RequestOpType,
61    ) -> BuckyResult<()> {
62
63        for full_path in list {
64            self.check_full_path(full_path.as_str(), op_type)?;
65        }
66
67        Ok(())
68    }
69
70    pub fn check_path_key(&self, path: &str, key: &str, op_type: RequestOpType) -> BuckyResult<()> {
71        // assert!(path.starts_with('/'));
72
73        let full_path = if path.ends_with('/') {
74            format!("{}{}", path, key)
75        } else {
76            format!("{}/{}", path, key)
77        };
78
79        self.check_full_path(&full_path, op_type)
80    }
81}
82
83#[cfg(test)]
84mod test {
85    use super::*;
86
87    #[test]
88    fn test() {
89        let limiter = OpEnvPathAccess::new("/a/b/c", AccessPermissions::ReadAndCall);
90        limiter
91            .check_full_path("/a/b", RequestOpType::Read)
92            .unwrap_err();
93        limiter
94            .check_full_path("/a/d", RequestOpType::Call)
95            .unwrap_err();
96        limiter
97            .check_full_path("/a/d/c1", RequestOpType::Call)
98            .unwrap_err();
99        limiter
100            .check_full_path("/", RequestOpType::Call)
101            .unwrap_err();
102        limiter
103            .check_full_path("/a", RequestOpType::Call)
104            .unwrap_err();
105
106        limiter
107            .check_full_path("/a/b/c", RequestOpType::Call)
108            .unwrap();
109        limiter
110            .check_full_path("/a/b/c/x", RequestOpType::Read)
111            .unwrap();
112
113        limiter
114            .check_full_path("/a/b/c", RequestOpType::Write)
115            .unwrap_err();
116        limiter
117            .check_full_path("/a/b/c/x", RequestOpType::Write)
118            .unwrap_err();
119    }
120}