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 info = store.0.get(code); | ||||
|     let info = if let Some(i) = info { | ||||
|         i.clone() | ||||
|         i.file.clone() | ||||
|     } else { | ||||
|         return not_found(req, data, true); | ||||
|     }; | ||||
|  | @ -165,7 +165,7 @@ async fn download_info( | |||
|     let store = data.state.read().await; | ||||
|     let info = store.0.get(code); | ||||
|     let info = if let Some(i) = info { | ||||
|         i.clone() | ||||
|         i.file.clone() | ||||
|     } else { | ||||
|         return not_found(req, data, true); | ||||
|     }; | ||||
|  |  | |||
							
								
								
									
										26
									
								
								src/state.rs
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								src/state.rs
									
										
									
									
									
								
							|  | @ -69,24 +69,32 @@ pub mod v1 { | |||
|         #[serde_as(as = "time::format_description::well_known::Rfc3339")] | ||||
|         pub expiry: OffsetDateTime, | ||||
|         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
 | ||||
|         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 { | ||||
|             StoredFile { | ||||
|                 name: old.name, | ||||
|                 size: old.size, | ||||
|                 modtime: old.modtime, | ||||
|                 expiry: old.expiry, | ||||
|                 contents: old.contents.map(FileSet::from), | ||||
|             StoredFileWithPassword { | ||||
|                 file: StoredFile { | ||||
|                     name: old.name, | ||||
|                     size: old.size, | ||||
|                     modtime: old.modtime, | ||||
|                     expiry: old.expiry, | ||||
|                     contents: old.contents.map(FileSet::from), | ||||
|                 }, | ||||
|                 password: None, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[derive(Debug, Default, Deserialize, Serialize)] | ||||
|     pub struct StoredFiles(pub HashMap<String, StoredFile>); | ||||
|     pub struct StoredFiles(pub HashMap<String, StoredFileWithPassword>); | ||||
| 
 | ||||
|     pub type State = StoredFiles; | ||||
| 
 | ||||
|  | @ -98,7 +106,7 @@ pub mod v1 { | |||
|             StoredFiles( | ||||
|                 old.0 | ||||
|                     .into_iter() | ||||
|                     .map(|(k, v)| (k, StoredFile::from(v))) | ||||
|                     .map(|(k, v)| (k, StoredFileWithPassword::from(v))) | ||||
|                     .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'-') | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|     if info.expiry < OffsetDateTime::now_utc() { | ||||
|  | @ -95,7 +95,7 @@ impl crate::AppData { | |||
|                 error!("Invalid key in persistent storage: {}", key); | ||||
|                 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); | ||||
|             } else { | ||||
|                 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
 | ||||
|     /// something's broken, or a u64 of the maximum allowed file size
 | ||||
|     /// 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; | ||||
|         if store.full(self.config.max_storage_size) { | ||||
|             return Err(FileAddError::Full); | ||||
|         } | ||||
|         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)); | ||||
|         } | ||||
|         store.0.insert(key, file); | ||||
|         store.0.insert(key, entry); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|  | @ -136,9 +136,9 @@ impl crate::AppData { | |||
|         let now = OffsetDateTime::now_utc(); | ||||
|         let mut store = self.state.write().await; | ||||
|         let old = std::mem::take(store.deref_mut()); | ||||
|         for (key, file) in old.0.into_iter() { | ||||
|             if file.expiry > now { | ||||
|                 store.0.insert(key, file); | ||||
|         for (key, value) in old.0.into_iter() { | ||||
|             if value.file.expiry > now { | ||||
|                 store.0.insert(key, value); | ||||
|             } else { | ||||
|                 info!("Deleting expired file {}", key); | ||||
|                 delete_file_if_exists(&self.config.storage_dir.join(&key)).await?; | ||||
|  | @ -150,7 +150,7 @@ impl crate::AppData { | |||
| 
 | ||||
| impl StoredFiles { | ||||
|     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 { | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ use unicode_normalization::UnicodeNormalization; | |||
| 
 | ||||
| use crate::{ | ||||
|     log_auth_failure, | ||||
|     store::{self, FileAddError, StoredFile}, | ||||
|     store::{self, FileAddError, StoredFile, StoredFileWithPassword}, | ||||
|     zip::FileSet, | ||||
|     AppData, | ||||
| }; | ||||
|  | @ -316,12 +316,14 @@ impl Uploader { | |||
|                         ) | ||||
|                     }; | ||||
|                 self.writer = Some(writer); | ||||
|                 let stored_file = StoredFile { | ||||
|                     name, | ||||
|                     size, | ||||
|                     modtime, | ||||
|                     expiry: OffsetDateTime::now_utc() + lifetime * time::Duration::DAY, | ||||
|                     contents, | ||||
|                 let stored_file = StoredFileWithPassword { | ||||
|                     file: StoredFile { | ||||
|                         name, | ||||
|                         size, | ||||
|                         modtime, | ||||
|                         expiry: OffsetDateTime::now_utc() + lifetime * time::Duration::DAY, | ||||
|                         contents, | ||||
|                     }, | ||||
|                     password: None, | ||||
|                 }; | ||||
|                 let app_data = self.app_data.clone(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue