1use crate::{
2 adapter::{Adapter, Filter},
3 error::{AdapterError, ModelError},
4 model::Model,
5 util::parse_csv_line,
6 Result,
7};
8
9#[cfg(feature = "runtime-async-std")]
10use async_std::{
11 fs::File as file,
12 io::prelude::*,
13 io::{
14 BufReader as ioBufReader, Error as ioError, ErrorKind as ioErrorKind,
15 },
16 path::Path as ioPath,
17 prelude::*,
18};
19
20#[cfg(feature = "runtime-tokio")]
21use std::path::Path as ioPath;
22#[cfg(feature = "runtime-tokio")]
23use tokio::{
24 fs::File as file,
25 io::{AsyncBufReadExt, AsyncWriteExt, BufReader as ioBufReader},
26};
27
28use async_trait::async_trait;
29use std::fmt::Write;
30
31pub struct FileAdapter<P> {
32 file_path: P,
33 is_filtered: bool,
34}
35
36type LoadPolicyFileHandler = fn(String, &mut dyn Model);
37type LoadFilteredPolicyFileHandler<'a> =
38 fn(String, &mut dyn Model, f: &Filter<'a>) -> bool;
39
40impl<P> FileAdapter<P>
41where
42 P: AsRef<ioPath> + Send + Sync,
43{
44 pub fn new(p: P) -> FileAdapter<P> {
45 FileAdapter {
46 file_path: p,
47 is_filtered: false,
48 }
49 }
50
51 pub fn new_filtered_adapter(p: P) -> FileAdapter<P> {
52 FileAdapter {
53 file_path: p,
54 is_filtered: true,
55 }
56 }
57
58 async fn load_policy_file(
59 &mut self,
60 m: &mut dyn Model,
61 handler: LoadPolicyFileHandler,
62 ) -> Result<()> {
63 let f = file::open(&self.file_path).await?;
64 let mut lines = ioBufReader::new(f).lines();
65 #[cfg(feature = "runtime-async-std")]
66 while let Some(line) = lines.next().await {
67 handler(line?, m)
68 }
69
70 #[cfg(feature = "runtime-tokio")]
71 while let Some(line) = lines.next_line().await? {
72 handler(line, m)
73 }
74
75 Ok(())
76 }
77
78 async fn load_filtered_policy_file<'a>(
79 &self,
80 m: &mut dyn Model,
81 filter: Filter<'a>,
82 handler: LoadFilteredPolicyFileHandler<'a>,
83 ) -> Result<bool> {
84 let f = file::open(&self.file_path).await?;
85 let mut lines = ioBufReader::new(f).lines();
86
87 let mut is_filtered = false;
88 #[cfg(feature = "runtime-async-std")]
89 while let Some(line) = lines.next().await {
90 if handler(line?, m, &filter) {
91 is_filtered = true;
92 }
93 }
94
95 #[cfg(feature = "runtime-tokio")]
96 while let Some(line) = lines.next_line().await? {
97 if handler(line, m, &filter) {
98 is_filtered = true;
99 }
100 }
101
102 Ok(is_filtered)
103 }
104
105 async fn save_policy_file(&self, text: String) -> Result<()> {
106 let mut file = file::create(&self.file_path).await?;
107 file.write_all(text.as_bytes()).await?;
108 Ok(())
109 }
110}
111
112#[async_trait]
113impl<P> Adapter for FileAdapter<P>
114where
115 P: AsRef<ioPath> + Send + Sync,
116{
117 async fn load_policy(&mut self, m: &mut dyn Model) -> Result<()> {
118 self.is_filtered = false;
119 self.load_policy_file(m, load_policy_line).await?;
120 Ok(())
121 }
122
123 async fn load_filtered_policy<'a>(
124 &mut self,
125 m: &mut dyn Model,
126 f: Filter<'a>,
127 ) -> Result<()> {
128 self.is_filtered = self
129 .load_filtered_policy_file(m, f, load_filtered_policy_line)
130 .await?;
131
132 Ok(())
133 }
134
135 async fn save_policy(&mut self, m: &mut dyn Model) -> Result<()> {
136 if self.file_path.as_ref().as_os_str().is_empty() {
137 return Err(std::io::Error::other(
138 "save policy failed, file path is empty",
139 )
140 .into());
141 }
142
143 let mut policies = String::new();
144 let ast_map = m.get_model().get("p").ok_or_else(|| {
145 ModelError::P("Missing policy definition in conf file".to_owned())
146 })?;
147
148 for (ptype, ast) in ast_map {
149 for rule in ast.get_policy() {
150 writeln!(policies, "{}, {}", ptype, rule.join(","))
151 .map_err(|e| AdapterError(e.into()))?;
152 }
153 }
154
155 if let Some(ast_map) = m.get_model().get("g") {
156 for (ptype, ast) in ast_map {
157 for rule in ast.get_policy() {
158 writeln!(policies, "{}, {}", ptype, rule.join(","))
159 .map_err(|e| AdapterError(e.into()))?;
160 }
161 }
162 }
163
164 self.save_policy_file(policies).await?;
165 Ok(())
166 }
167
168 async fn clear_policy(&mut self) -> Result<()> {
169 self.save_policy_file(String::new()).await?;
170 Ok(())
171 }
172
173 async fn add_policy(
174 &mut self,
175 _sec: &str,
176 _ptype: &str,
177 _rule: Vec<String>,
178 ) -> Result<bool> {
179 Ok(true)
181 }
182
183 async fn add_policies(
184 &mut self,
185 _sec: &str,
186 _ptype: &str,
187 _rules: Vec<Vec<String>>,
188 ) -> Result<bool> {
189 Ok(true)
191 }
192
193 async fn remove_policy(
194 &mut self,
195 _sec: &str,
196 _ptype: &str,
197 _rule: Vec<String>,
198 ) -> Result<bool> {
199 Ok(true)
201 }
202
203 async fn remove_policies(
204 &mut self,
205 _sec: &str,
206 _ptype: &str,
207 _rule: Vec<Vec<String>>,
208 ) -> Result<bool> {
209 Ok(true)
211 }
212
213 async fn remove_filtered_policy(
214 &mut self,
215 _sec: &str,
216 _ptype: &str,
217 _field_index: usize,
218 _field_values: Vec<String>,
219 ) -> Result<bool> {
220 Ok(true)
222 }
223
224 fn is_filtered(&self) -> bool {
225 self.is_filtered
226 }
227}
228
229fn load_policy_line(line: String, m: &mut dyn Model) {
230 if line.is_empty() || line.starts_with('#') {
231 return;
232 }
233
234 if let Some(tokens) = parse_csv_line(line) {
235 let key = &tokens[0];
236
237 if let Some(ref sec) = key.chars().next().map(|x| x.to_string()) {
238 if let Some(ast_map) = m.get_mut_model().get_mut(sec) {
239 if let Some(ast) = ast_map.get_mut(key) {
240 ast.policy.insert(tokens[1..].to_vec());
241 }
242 }
243 }
244 }
245}
246
247fn load_filtered_policy_line(
248 line: String,
249 m: &mut dyn Model,
250 f: &Filter<'_>,
251) -> bool {
252 if line.is_empty() || line.starts_with('#') {
253 return false;
254 }
255
256 if let Some(tokens) = parse_csv_line(line) {
257 let key = &tokens[0];
258
259 let mut is_filtered = false;
260 if let Some(ref sec) = key.chars().next().map(|x| x.to_string()) {
261 if sec == "p" {
262 for (i, rule) in f.p.iter().enumerate() {
263 if !rule.is_empty() && rule != &tokens[i + 1] {
264 is_filtered = true;
265 }
266 }
267 }
268 if sec == "g" {
269 for (i, rule) in f.g.iter().enumerate() {
270 if !rule.is_empty() && rule != &tokens[i + 1] {
271 is_filtered = true;
272 }
273 }
274 }
275 if !is_filtered {
276 if let Some(ast_map) = m.get_mut_model().get_mut(sec) {
277 if let Some(ast) = ast_map.get_mut(key) {
278 ast.policy.insert(tokens[1..].to_vec());
279 }
280 }
281 }
282 }
283
284 is_filtered
285 } else {
286 false
287 }
288}