ppaass_v3_common/user/repo/
fs.rs1use crate::crypto::RsaCrypto;
2use crate::error::CommonError;
3use crate::user::{UserInfo, UserInfoRepository};
4use accessory::Accessors;
5use chrono::{DateTime, Utc};
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fs::{read_dir, File};
10use std::future::Future;
11use std::io::Read;
12use std::path::{Path, PathBuf};
13use std::sync::Arc;
14use std::time::Duration;
15use tokio::sync::RwLock;
16use tokio::time::sleep;
17use tracing::error;
18use zip::ZipArchive;
19pub const USER_INFO_ADDITION_INFO_EXPIRED_DATE_TIME: &str = "expired_date_time";
20pub const USER_INFO_ADDITION_INFO_PROXY_SERVERS: &str = "proxy_servers";
21pub const FS_USER_INFO_CONFIG_FILE_NAME: &str = "userinfo.toml";
22pub trait FsUserInfoContent {
23 fn public_key_file_relative_path(&self) -> &str;
24 fn private_key_file_relative_path(&self) -> &str;
25}
26#[derive(Debug, Serialize, Deserialize, Accessors)]
27pub struct FsAgentUserInfoContent {
28 #[access(get)]
29 public_key_file_relative_path: String,
30 #[access(get)]
31 private_key_file_relative_path: String,
32 #[access(get)]
33 proxy_servers: Vec<String>,
34}
35impl FsAgentUserInfoContent {
36 pub fn new(
37 proxy_servers: Vec<String>,
38 public_key_file_relative_path: String,
39 private_key_file_relative_path: String,
40 ) -> Self {
41 Self {
42 proxy_servers,
43 public_key_file_relative_path,
44 private_key_file_relative_path,
45 }
46 }
47}
48impl FsUserInfoContent for FsAgentUserInfoContent {
49 fn public_key_file_relative_path(&self) -> &str {
50 &self.public_key_file_relative_path
51 }
52 fn private_key_file_relative_path(&self) -> &str {
53 &self.private_key_file_relative_path
54 }
55}
56#[derive(Debug, Serialize, Deserialize, Accessors)]
57pub struct FsProxyUserInfoContent {
58 #[access(get)]
59 expired_date_time: Option<DateTime<Utc>>,
60 #[access(get)]
61 public_key_file_relative_path: String,
62 #[access(get)]
63 private_key_file_relative_path: String,
64}
65impl FsProxyUserInfoContent {
66 pub fn new(
67 expired_date_time: Option<DateTime<Utc>>,
68 public_key_file_relative_path: String,
69 private_key_file_relative_path: String,
70 ) -> Self {
71 Self {
72 expired_date_time,
73 public_key_file_relative_path,
74 private_key_file_relative_path,
75 }
76 }
77}
78impl FsUserInfoContent for FsProxyUserInfoContent {
79 fn public_key_file_relative_path(&self) -> &str {
80 &self.public_key_file_relative_path
81 }
82 fn private_key_file_relative_path(&self) -> &str {
83 &self.private_key_file_relative_path
84 }
85}
86#[derive(Debug)]
87pub struct FileSystemUserInfoRepository {
88 user_info_storage: Arc<RwLock<HashMap<String, Arc<RwLock<UserInfo>>>>>,
89}
90impl FileSystemUserInfoRepository {
91 pub async fn new<T, F, Fut>(
92 refresh_interval: u64,
93 user_repo_dir_path: &Path,
94 prepare_additional_info: F,
95 ) -> Result<Self, CommonError>
96 where
97 T: FsUserInfoContent + DeserializeOwned + Send + Sync + 'static,
98 Fut: Future<Output = ()> + Send + Sync + 'static,
99 F: Fn(Arc<RwLock<UserInfo>>, T) -> Fut + Clone + Send + Sync + 'static,
100 {
101 let user_info_storage = Arc::new(RwLock::new(HashMap::new()));
102 {
103 let user_info_storage = user_info_storage.clone();
104 let user_repo_dir_path = user_repo_dir_path.to_owned();
105 if let Err(e) = Self::fill_repo_storage(
106 prepare_additional_info.clone(),
107 user_info_storage.clone(),
108 &user_repo_dir_path,
109 )
110 .await
111 {
112 error!("Fail to build user repo:{e:?}");
113 }
114 tokio::spawn(async move {
115 loop {
116 if let Err(e) = Self::fill_repo_storage(
117 prepare_additional_info.clone(),
118 user_info_storage.clone(),
119 &user_repo_dir_path,
120 )
121 .await
122 {
123 error!("Fail to build user repo:{e:?}");
124 }
125 sleep(Duration::from_secs(refresh_interval)).await;
126 }
127 });
128 }
129
130 Ok(Self { user_info_storage })
131 }
132 async fn fill_repo_storage<F, T, Fut>(
133 prepare_additional_info: F,
134 user_info_storage: Arc<RwLock<HashMap<String, Arc<RwLock<UserInfo>>>>>,
135 user_repo_dir_path: &PathBuf,
136 ) -> Result<(), CommonError>
137 where
138 T: FsUserInfoContent + DeserializeOwned + Send + Sync + 'static,
139 Fut: Future<Output = ()> + Send + Sync + 'static,
140 F: Fn(Arc<RwLock<UserInfo>>, T) -> Fut + Clone + Send + Sync + 'static,
141 {
142 let user_info_dir = read_dir(&user_repo_dir_path)?;
143 for entry in user_info_dir.into_iter() {
144 let Ok(entry) = entry else {
145 error!("Fail to read user info directory [{user_repo_dir_path:?}]");
146 continue;
147 };
148 let file_name = entry.file_name();
149 let file_name = file_name.to_str();
150 let Some(file_name) = file_name else {
151 error!("Fail to read [{user_repo_dir_path:?}{file_name:?}].",);
152 continue;
153 };
154 let file_name_parts = file_name.split('.').collect::<Vec<&str>>();
155 if file_name_parts.len() < 2 {
156 error!(
157 "Fail to read [{user_repo_dir_path:?}{file_name:?}] because of the file name is not in 2 parts",
158 );
159 continue;
160 }
161 let username = file_name_parts[0];
162 let user_zip_file_path = user_repo_dir_path.join(format!("{}.zip", username));
163 let user_zip_file = match File::open(user_zip_file_path) {
164 Ok(user_zip_file) => user_zip_file,
165 Err(e) => {
166 error!("Fail to read user zip file: {e:?}");
167 continue;
168 }
169 };
170 let mut user_zip_archive = match ZipArchive::new(user_zip_file) {
171 Ok(user_zip_archive) => user_zip_archive,
172 Err(e) => {
173 error!("Fail to read user zip archive: {e:?}");
174 continue;
175 }
176 };
177 let mut user_info_config_file_content = String::new();
178 {
179 let mut user_info_zip_file =
180 match user_zip_archive.by_name(FS_USER_INFO_CONFIG_FILE_NAME) {
181 Ok(user_info_file) => user_info_file,
182 Err(e) => {
183 error!("Fail to read user info file from zip archive: {e:?}");
184 continue;
185 }
186 };
187 if let Err(e) =
188 user_info_zip_file.read_to_string(&mut user_info_config_file_content)
189 {
190 error!("Fail to read user info file content from zip archive: {e:?}");
191 continue;
192 };
193 }
194 let user_info_content = match toml::from_str::<T>(&user_info_config_file_content) {
195 Ok(config) => config,
196 Err(e) => {
197 error!("Fail to parse user info config file [{user_repo_dir_path:?}]: {e:?}");
198 continue;
199 }
200 };
201 let mut public_key_file_content = String::new();
202 {
203 let mut public_key_zip_file = match user_zip_archive
204 .by_name(user_info_content.public_key_file_relative_path())
205 {
206 Ok(user_info_file) => user_info_file,
207 Err(e) => {
208 error!("Fail to read public key file from zip archive: {e:?}");
209 continue;
210 }
211 };
212 if let Err(e) = public_key_zip_file.read_to_string(&mut public_key_file_content) {
213 error!("Fail to read public key file content from zip archive: {e:?}");
214 continue;
215 };
216 }
217 let mut private_key_file_content = String::new();
218 {
219 let mut private_key_zip_file = match user_zip_archive
220 .by_name(user_info_content.private_key_file_relative_path())
221 {
222 Ok(user_info_file) => user_info_file,
223 Err(e) => {
224 error!("Fail to read private key file from zip archive: {e:?}");
225 continue;
226 }
227 };
228 if let Err(e) = private_key_zip_file.read_to_string(&mut private_key_file_content) {
229 error!("Fail to read private key file content from zip archive: {e:?}");
230 continue;
231 };
232 }
233 let Ok(rsa_crypto) = RsaCrypto::new(public_key_file_content, private_key_file_content)
234 else {
235 error!("Fail to create agent_user crypto for user: {username}.");
236 continue;
237 };
238 let user_info = Arc::new(RwLock::new(UserInfo::new(rsa_crypto)));
239 prepare_additional_info(user_info.clone(), user_info_content).await;
240 let mut user_info_storage = user_info_storage.write().await;
241 user_info_storage.insert(username.to_string(), user_info);
242 }
243 Ok(())
244 }
245}
246
247#[async_trait::async_trait]
248impl UserInfoRepository for FileSystemUserInfoRepository {
249 async fn get_user(&self, username: &str) -> Result<Option<Arc<RwLock<UserInfo>>>, CommonError> {
250 match self.user_info_storage.read().await.get(username) {
251 None => Ok(None),
252 Some(user_info) => Ok(Some(user_info.clone())),
253 }
254 }
255 async fn list_all_users(&self) -> Result<Vec<Arc<RwLock<UserInfo>>>, CommonError> {
256 let user_info_storage = self.user_info_storage.read().await;
257 Ok(user_info_storage
258 .values()
259 .map(|user_info| user_info.clone())
260 .collect())
261 }
262}