Keep passwords out of endpoint responses while preserving v1 schema
This commit is contained in:
		
							parent
							
								
									aef58d133b
								
							
						
					
					
						commit
						c7ceb4113b
					
				
					 4 changed files with 37 additions and 27 deletions
				
			
		|  | @ -107,7 +107,7 @@ async fn handle_download( | ||||||
|     let store = data.state.read().await; |     let store = data.state.read().await; | ||||||
|     let info = store.0.get(code); |     let info = store.0.get(code); | ||||||
|     let info = if let Some(i) = info { |     let info = if let Some(i) = info { | ||||||
|         i.clone() |         i.file.clone() | ||||||
|     } else { |     } else { | ||||||
|         return not_found(req, data, true); |         return not_found(req, data, true); | ||||||
|     }; |     }; | ||||||
|  | @ -165,7 +165,7 @@ async fn download_info( | ||||||
|     let store = data.state.read().await; |     let store = data.state.read().await; | ||||||
|     let info = store.0.get(code); |     let info = store.0.get(code); | ||||||
|     let info = if let Some(i) = info { |     let info = if let Some(i) = info { | ||||||
|         i.clone() |         i.file.clone() | ||||||
|     } else { |     } else { | ||||||
|         return not_found(req, data, true); |         return not_found(req, data, true); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								src/state.rs
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								src/state.rs
									
										
									
									
									
								
							|  | @ -69,24 +69,32 @@ pub mod v1 { | ||||||
|         #[serde_as(as = "time::format_description::well_known::Rfc3339")] |         #[serde_as(as = "time::format_description::well_known::Rfc3339")] | ||||||
|         pub expiry: OffsetDateTime, |         pub expiry: OffsetDateTime, | ||||||
|         pub contents: Option<FileSet>, |         pub contents: Option<FileSet>, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[derive(Debug, Clone, Deserialize, Serialize)] | ||||||
|  |     pub struct StoredFileWithPassword { | ||||||
|  |         #[serde(flatten)] | ||||||
|  |         pub file: StoredFile, | ||||||
|         /// None password means the admin page can't be accessed
 |         /// None password means the admin page can't be accessed
 | ||||||
|         pub password: Option<String>, |         pub password: Option<String>, | ||||||
|     } |     } | ||||||
|     impl From<super::v0::StoredFile> for StoredFile { |     impl From<super::v0::StoredFile> for StoredFileWithPassword { | ||||||
|         fn from(old: super::v0::StoredFile) -> Self { |         fn from(old: super::v0::StoredFile) -> Self { | ||||||
|             StoredFile { |             StoredFileWithPassword { | ||||||
|  |                 file: StoredFile { | ||||||
|                     name: old.name, |                     name: old.name, | ||||||
|                     size: old.size, |                     size: old.size, | ||||||
|                     modtime: old.modtime, |                     modtime: old.modtime, | ||||||
|                     expiry: old.expiry, |                     expiry: old.expiry, | ||||||
|                     contents: old.contents.map(FileSet::from), |                     contents: old.contents.map(FileSet::from), | ||||||
|  |                 }, | ||||||
|                 password: None, |                 password: None, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[derive(Debug, Default, Deserialize, Serialize)] |     #[derive(Debug, Default, Deserialize, Serialize)] | ||||||
|     pub struct StoredFiles(pub HashMap<String, StoredFile>); |     pub struct StoredFiles(pub HashMap<String, StoredFileWithPassword>); | ||||||
| 
 | 
 | ||||||
|     pub type State = StoredFiles; |     pub type State = StoredFiles; | ||||||
| 
 | 
 | ||||||
|  | @ -98,7 +106,7 @@ pub mod v1 { | ||||||
|             StoredFiles( |             StoredFiles( | ||||||
|                 old.0 |                 old.0 | ||||||
|                     .into_iter() |                     .into_iter() | ||||||
|                     .map(|(k, v)| (k, StoredFile::from(v))) |                     .map(|(k, v)| (k, StoredFileWithPassword::from(v))) | ||||||
|                     .collect(), |                     .collect(), | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								src/store.rs
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								src/store.rs
									
										
									
									
									
								
							|  | @ -28,7 +28,7 @@ pub fn is_valid_storage_code(s: &str) -> bool { | ||||||
|         .all(|c| c.is_ascii_alphanumeric() || c == &b'-') |         .all(|c| c.is_ascii_alphanumeric() || c == &b'-') | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub use crate::state::v1::{StoredFile, StoredFiles}; | pub use crate::state::v1::{StoredFile, StoredFileWithPassword, StoredFiles}; | ||||||
| 
 | 
 | ||||||
| async fn is_valid_entry(key: &str, info: &StoredFile, storage_dir: &Path) -> bool { | async fn is_valid_entry(key: &str, info: &StoredFile, storage_dir: &Path) -> bool { | ||||||
|     if info.expiry < OffsetDateTime::now_utc() { |     if info.expiry < OffsetDateTime::now_utc() { | ||||||
|  | @ -95,7 +95,7 @@ impl crate::AppData { | ||||||
|                 error!("Invalid key in persistent storage: {}", key); |                 error!("Invalid key in persistent storage: {}", key); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             if is_valid_entry(&key, &info, &self.config.storage_dir).await { |             if is_valid_entry(&key, &info.file, &self.config.storage_dir).await { | ||||||
|                 store.0.insert(key, info); |                 store.0.insert(key, info); | ||||||
|             } else { |             } else { | ||||||
|                 info!("Deleting file {}", key); |                 info!("Deleting file {}", key); | ||||||
|  | @ -108,16 +108,16 @@ impl crate::AppData { | ||||||
|     /// Attempts to add a file to the store. Returns an I/O error if
 |     /// Attempts to add a file to the store. Returns an I/O error if
 | ||||||
|     /// something's broken, or a u64 of the maximum allowed file size
 |     /// something's broken, or a u64 of the maximum allowed file size
 | ||||||
|     /// if the file was too big, or a unit if everything worked.
 |     /// if the file was too big, or a unit if everything worked.
 | ||||||
|     pub async fn add_file(&self, key: String, file: StoredFile) -> Result<(), FileAddError> { |     pub async fn add_file(&self, key: String, entry: StoredFileWithPassword) -> Result<(), FileAddError> { | ||||||
|         let mut store = self.state.write().await; |         let mut store = self.state.write().await; | ||||||
|         if store.full(self.config.max_storage_size) { |         if store.full(self.config.max_storage_size) { | ||||||
|             return Err(FileAddError::Full); |             return Err(FileAddError::Full); | ||||||
|         } |         } | ||||||
|         let available_size = store.available_size(self.config.max_storage_size); |         let available_size = store.available_size(self.config.max_storage_size); | ||||||
|         if file.size > available_size { |         if entry.file.size > available_size { | ||||||
|             return Err(FileAddError::TooBig(available_size)); |             return Err(FileAddError::TooBig(available_size)); | ||||||
|         } |         } | ||||||
|         store.0.insert(key, file); |         store.0.insert(key, entry); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -136,9 +136,9 @@ impl crate::AppData { | ||||||
|         let now = OffsetDateTime::now_utc(); |         let now = OffsetDateTime::now_utc(); | ||||||
|         let mut store = self.state.write().await; |         let mut store = self.state.write().await; | ||||||
|         let old = std::mem::take(store.deref_mut()); |         let old = std::mem::take(store.deref_mut()); | ||||||
|         for (key, file) in old.0.into_iter() { |         for (key, value) in old.0.into_iter() { | ||||||
|             if file.expiry > now { |             if value.file.expiry > now { | ||||||
|                 store.0.insert(key, file); |                 store.0.insert(key, value); | ||||||
|             } else { |             } else { | ||||||
|                 info!("Deleting expired file {}", key); |                 info!("Deleting expired file {}", key); | ||||||
|                 delete_file_if_exists(&self.config.storage_dir.join(&key)).await?; |                 delete_file_if_exists(&self.config.storage_dir.join(&key)).await?; | ||||||
|  | @ -150,7 +150,7 @@ impl crate::AppData { | ||||||
| 
 | 
 | ||||||
| impl StoredFiles { | impl StoredFiles { | ||||||
|     fn total_size(&self) -> u64 { |     fn total_size(&self) -> u64 { | ||||||
|         self.0.iter().fold(0, |acc, (_, f)| acc + f.size) |         self.0.iter().fold(0, |acc, (_, v)| acc + v.file.size) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn available_size(&self, max_storage_size: u64) -> u64 { |     pub fn available_size(&self, max_storage_size: u64) -> u64 { | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ use unicode_normalization::UnicodeNormalization; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     log_auth_failure, |     log_auth_failure, | ||||||
|     store::{self, FileAddError, StoredFile}, |     store::{self, FileAddError, StoredFile, StoredFileWithPassword}, | ||||||
|     zip::FileSet, |     zip::FileSet, | ||||||
|     AppData, |     AppData, | ||||||
| }; | }; | ||||||
|  | @ -316,12 +316,14 @@ impl Uploader { | ||||||
|                         ) |                         ) | ||||||
|                     }; |                     }; | ||||||
|                 self.writer = Some(writer); |                 self.writer = Some(writer); | ||||||
|                 let stored_file = StoredFile { |                 let stored_file = StoredFileWithPassword { | ||||||
|  |                     file: StoredFile { | ||||||
|                         name, |                         name, | ||||||
|                         size, |                         size, | ||||||
|                         modtime, |                         modtime, | ||||||
|                         expiry: OffsetDateTime::now_utc() + lifetime * time::Duration::DAY, |                         expiry: OffsetDateTime::now_utc() + lifetime * time::Duration::DAY, | ||||||
|                         contents, |                         contents, | ||||||
|  |                     }, | ||||||
|                     password: None, |                     password: None, | ||||||
|                 }; |                 }; | ||||||
|                 let app_data = self.app_data.clone(); |                 let app_data = self.app_data.clone(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue