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