IMAPServer_shared/mailbox/
mod.rs1use std::path::Path;
2
3use argonautica::{Hasher, Verifier};
4use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
5use futures::compat::Future01CompatExt;
6use futures::StreamExt;
7use log::debug;
8use log::warn;
9use rand::prelude::*;
10use tokio::fs::{create_dir_all, metadata, read_dir};
11
12use crate::config::Config;
13use crate::database::establish_connection;
14use crate::models::{NewUser, User};
15use crate::schema::users;
16use crate::schema::users::dsl::*;
17
18#[derive(Clone)]
19pub struct Mailbox {
20 pub user: String,
21 pub mailbox_root: String,
22 password_hash: String,
23}
24
25fn string_to_static_str(s: String) -> &'static str {
26 Box::leak(s.into_boxed_str())
27}
28
29impl Mailbox {
30 pub async fn new(user: String, password: String) -> Option<Self> {
31 let config = Config::load().await.expect("unable to load config");
32
33 let mut hasher = Hasher::default();
34 let password_hash_new = hasher
35 .with_password(password)
36 .with_secret_key(config.shared_secret)
37 .hash_non_blocking()
38 .compat()
39 .await
40 .expect("unable to hash password");
41
42 let mut rng = StdRng::from_entropy();
43
44 #[allow(unused_mut)]
46 let mut random_number: String;
47
48 if rng.gen() {
49 let random_number_int: i32 = rng.gen_range(0, 2 ^ 32 - 1);
50
51 random_number = format!("{:?}", random_number_int);
52 } else {
53 warn!("Unable to generate random number");
54 return None;
55 }
56
57 let connection = establish_connection();
58 let user_local = user.clone();
59 let results: Result<User, diesel::result::Error> = users
60 .filter(email.eq(&user))
61 .limit(1)
62 .get_result::<User>(&connection);
63
64 match results {
65 Ok(m) => {
66 let mailbox_root = format!("{}/{}", config.mailbox_root, m.email);
67 return Some(Mailbox {
68 mailbox_root,
69 user,
70 password_hash: m.password_hash,
71 });
72 }
73 Err(_) => {
74 let new_user = NewUser {
75 email: &user,
76 password_hash: &password_hash_new,
77 uid_validity_identifier: &random_number,
78 };
79
80 diesel::insert_into(users::table)
81 .values(&new_user)
82 .execute(&connection)
83 .expect("Failed to add new User");
84
85 let mailbox_root = format!("{}/{}", config.mailbox_root, user);
86
87 return Some(Mailbox {
88 mailbox_root,
89 user: user_local,
90 password_hash: password_hash_new,
91 });
92 }
93 }
94 }
95
96 pub async fn load(user: String) -> Option<Self> {
97 let connection = establish_connection();
98 let config = Config::load().await.expect("unable to load config");
99 let user_local = user.clone();
100
101 let results: Result<User, diesel::result::Error> = users
102 .filter(email.eq(user))
103 .limit(1)
104 .get_result::<User>(&connection);
105
106 match results {
107 Ok(results) => {
108 let mailbox_root = format!("{}/{}", config.mailbox_root, results.email);
109 Some(Mailbox {
110 mailbox_root,
111 user: user_local,
112 password_hash: results.password_hash,
113 })
114 }
115 _ => None,
116 }
117 }
118
119 pub async fn load_all() -> Option<Vec<Self>> {
120 let connection = establish_connection();
121 let config = Config::load().await.expect("unable to load config");
122
123 let results: Vec<User> = users
124 .load::<User>(&connection)
125 .expect("Error getting Mailboxes");
126
127 let mut returns: Vec<Self> = Vec::new();
128
129 for entry in &results {
130 let mailbox_root = format!("{}/{}", config.mailbox_root, entry.email);
131 returns.push(Mailbox {
132 mailbox_root,
133 user: entry.email.clone(),
134 password_hash: entry.password_hash.clone(),
135 })
136 }
137
138 Some(returns)
139 }
140
141 pub async fn check_password_plain(&self, password: String) -> Result<(), ()> {
142 let config = Config::load().await.expect("unable to load config");
143 let local_hash = self.password_hash.clone();
144
145 let mut verifier = Verifier::default();
146 let verified = verifier
147 .with_hash(local_hash)
148 .with_password(password)
149 .with_secret_key(config.shared_secret)
150 .verify_non_blocking()
151 .compat()
152 .await;
153 match verified {
154 Ok(v) => {
155 if v {
156 return Ok(());
157 } else {
158 return Err(());
159 }
160 }
161 Err(_) => {
162 return Err(());
163 }
164 }
165 }
166
167 pub async fn get_lsub(&self, args: Vec<&str>) -> Option<Vec<String>> {
168 if args.len() == 4 {
169 debug!("get_lsub 4");
170 } else if args.len() == 5 {
171 debug!("get_lsub 5");
172 }
173
174 let searched = args.get(args.len() - 1).expect("unable to get searched path").replace("\"", "");
175
176 let mut dirs = read_dir(self.mailbox_root.to_owned())
177 .await
178 .expect("unable to read dir");
179
180 let mut dirs_lsub: Vec<&str> = Vec::new();
181
182 while let Some(dir) = dirs.next().await {
183 let dir = dir.expect("unable to get dir");
184 if dir.file_name().into_string().unwrap() != searched && searched != "*" { continue; }
186 let subscribed_str: &str = "(subscribed)";
187 if args.contains(&subscribed_str) {
188 let path_string = format!(
189 "* LSUB (\\Subscribed) \".\" {}\r\n",
190 dir.file_name()
191 .into_string()
192 .expect("unable to get filename")
193 );
194 let path_string = string_to_static_str(path_string);
195 dirs_lsub.push(path_string);
196 continue;
197 } else {
198 let path_string = format!(
199 "* LSUB (\\HasNoChildren) \".\" {}\r\n",
200 dir.file_name()
201 .into_string()
202 .expect("unable to get filename")
203 );
204 let path_string = string_to_static_str(path_string);
205 dirs_lsub.push(path_string);
206 continue;
207 }
208 }
209
210 if dirs_lsub.len() > 0 {
211 let dirs_lsub: Vec<String> = dirs_lsub.iter().map(|s| (*s).to_string()).collect();
212 Some(dirs_lsub)
213 } else {
214 None
215 }
216 }
217
218 pub async fn get_list(&self, args: Vec<&str>) -> Option<Vec<String>> {
219 if args.len() == 4 {
220 debug!("get_list 4");
221 } else if args.len() == 5 {
222 debug!("get_list 5");
223 }
224
225 let searched = args.get(args.len() - 1).expect("unable to get searched path").replace("\"", "");
226
227 let mut dirs = read_dir(self.mailbox_root.to_owned())
228 .await
229 .expect("unable to read dir");
230
231 let mut dirs_list: Vec<&str> = Vec::new();
232
233 while let Some(dir) = dirs.next().await {
234 let dir = dir.expect("unable to get dir");
235 if dir.file_name().into_string().unwrap() != searched && searched != "*" { continue; }
237 let subscribed_str: &str = "(subscribed)";
238 if args.contains(&subscribed_str) {
239 let path_string = format!(
241 "* LIST (\\Subscribed) \".\" {}\r\n",
242 dir.file_name()
243 .into_string()
244 .expect("unable to get filename")
245 );
246 let path_string = string_to_static_str(path_string);
247 dirs_list.push(path_string);
248 continue;
249 } else {
250 let path_string = format!(
252 "* LIST (\\HasNoChildren) \".\" {}\r\n",
253 dir.file_name()
254 .into_string()
255 .expect("unable to get filename")
256 );
257 let path_string = string_to_static_str(path_string);
258 dirs_list.push(path_string);
259 continue;
260 }
261 }
262
263 if dirs_list.len() > 0 {
264 let dirs_list: Vec<String> = dirs_list.iter().map(|s| (*s).to_string()).collect();
265 Some(dirs_list)
266 } else {
267 None
268 }
269 }
270
271 pub async fn check_mailbox_root(&self) -> Result<(), std::io::Error> {
272 self.check_mailbox_folder("").await?;
273 Ok(())
274 }
275
276 pub async fn check_mailbox_folder<P>(&self, path_part: P) -> Result<(), std::io::Error>
277 where
278 P: AsRef<Path>,
279 {
280 let path = Path::new(&self.mailbox_root);
281 let path = path.join(&path_part.as_ref().to_owned());
282 let metadata = metadata(&path).await;
283 match metadata {
284 Err(_) => {
285 warn!("Mailbox folder {:?} was missing. Recreating", &path);
286
287 create_dir_all(path).await?
288 }
289 Ok(_) => {}
290 }
291 Ok(())
292 }
293
294 pub async fn create_folder<P>(&self, path: P) -> Result<(), std::io::Error>
295 where
296 P: AsRef<Path>,
297 {
298 let path = &path.as_ref().to_owned();
299 self.check_mailbox_folder(path).await?;
300
301 Ok(())
302 }
303}