fix bug where meta files where not auto-created upon starting + fix bug where meta json files were actually binary + improved access control to database instances
This commit is contained in:
		| @@ -76,9 +76,12 @@ async fn main() { | |||||||
|     // new server |     // new server | ||||||
|     let mut server = server::Server::new(option).await; |     let mut server = server::Server::new(option).await; | ||||||
|  |  | ||||||
|     // Initialize the default database storage |     // Initialize the default database storage (creates 0.db) | ||||||
|     let _ = server.current_storage(); |     let _ = server.current_storage(); | ||||||
|  |  | ||||||
|  |     // Ensure default meta for DB 0 exists (public by default if missing) | ||||||
|  |     let _ = herodb::rpc::RpcServerImpl::load_meta_static(&server.option.dir, 0).await; | ||||||
|  |  | ||||||
|     // Add a small delay to ensure the port is ready |     // Add a small delay to ensure the port is ready | ||||||
|     tokio::time::sleep(std::time::Duration::from_millis(100)).await; |     tokio::time::sleep(std::time::Duration::from_millis(100)).await; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								src/rpc.rs
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/rpc.rs
									
									
									
									
									
								
							| @@ -239,29 +239,25 @@ impl RpcServerImpl { | |||||||
|     pub async fn load_meta_static(base_dir: &str, db_id: u64) -> Result<DatabaseMeta, jsonrpsee::types::ErrorObjectOwned> { |     pub async fn load_meta_static(base_dir: &str, db_id: u64) -> Result<DatabaseMeta, jsonrpsee::types::ErrorObjectOwned> { | ||||||
|         let meta_path = std::path::PathBuf::from(base_dir).join(format!("{}_meta.json", db_id)); |         let meta_path = std::path::PathBuf::from(base_dir).join(format!("{}_meta.json", db_id)); | ||||||
|  |  | ||||||
|         // If meta file doesn't exist, return default |         // If meta file doesn't exist, create and persist default | ||||||
|         if !meta_path.exists() { |         if !meta_path.exists() { | ||||||
|             return Ok(DatabaseMeta { |             let default_meta = DatabaseMeta { | ||||||
|                 public: true, |                 public: true, | ||||||
|                 keys: HashMap::new(), |                 keys: HashMap::new(), | ||||||
|             }); |             }; | ||||||
|  |             // Persist default metadata to disk | ||||||
|  |             Self::save_meta_static(base_dir, db_id, &default_meta).await?; | ||||||
|  |             return Ok(default_meta); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Read file |         // Read file as UTF-8 JSON | ||||||
|         let content = std::fs::read(&meta_path) |         let json_str = std::fs::read_to_string(&meta_path) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
|                 format!("Failed to read meta file: {}", e), |                 format!("Failed to read meta file: {}", e), | ||||||
|                 None::<()> |                 None::<()> | ||||||
|             ))?; |             ))?; | ||||||
|  |  | ||||||
|         let json_str = String::from_utf8(content) |  | ||||||
|             .map_err(|_| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                 -32000, |  | ||||||
|                 "Invalid UTF-8 in meta file", |  | ||||||
|                 None::<()> |  | ||||||
|             ))?; |  | ||||||
|  |  | ||||||
|         serde_json::from_str(&json_str) |         serde_json::from_str(&json_str) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
| @@ -274,7 +270,7 @@ impl RpcServerImpl { | |||||||
|     async fn load_meta(&self, db_id: u64) -> Result<DatabaseMeta, jsonrpsee::types::ErrorObjectOwned> { |     async fn load_meta(&self, db_id: u64) -> Result<DatabaseMeta, jsonrpsee::types::ErrorObjectOwned> { | ||||||
|         let meta_path = std::path::PathBuf::from(&self.base_dir).join(format!("{}_meta.json", db_id)); |         let meta_path = std::path::PathBuf::from(&self.base_dir).join(format!("{}_meta.json", db_id)); | ||||||
|  |  | ||||||
|         // If meta file doesn't exist, create default |         // If meta file doesn't exist, create and persist default | ||||||
|         if !meta_path.exists() { |         if !meta_path.exists() { | ||||||
|             let default_meta = DatabaseMeta { |             let default_meta = DatabaseMeta { | ||||||
|                 public: true, |                 public: true, | ||||||
| @@ -284,46 +280,14 @@ impl RpcServerImpl { | |||||||
|             return Ok(default_meta); |             return Ok(default_meta); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Read and potentially decrypt |         // Read file as UTF-8 JSON (meta files are always plain JSON) | ||||||
|         let content = std::fs::read(&meta_path) |         let json_str = std::fs::read_to_string(&meta_path) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
|                 format!("Failed to read meta file: {}", e), |                 format!("Failed to read meta file: {}", e), | ||||||
|                 None::<()> |                 None::<()> | ||||||
|             ))?; |             ))?; | ||||||
|  |  | ||||||
|         let json_str = if db_id >= 10 { |  | ||||||
|             // Encrypted database, decrypt meta |  | ||||||
|             if let Some(key) = self.encryption_keys.read().await.get(&db_id).and_then(|k| k.as_ref()) { |  | ||||||
|                 use crate::crypto::CryptoFactory; |  | ||||||
|                 let crypto = CryptoFactory::new(key.as_bytes()); |  | ||||||
|                 String::from_utf8(crypto.decrypt(&content) |  | ||||||
|                     .map_err(|_| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                         -32000, |  | ||||||
|                         "Failed to decrypt meta file", |  | ||||||
|                         None::<()> |  | ||||||
|                     ))?) |  | ||||||
|                     .map_err(|_| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                         -32000, |  | ||||||
|                         "Invalid UTF-8 in decrypted meta", |  | ||||||
|                         None::<()> |  | ||||||
|                     ))? |  | ||||||
|             } else { |  | ||||||
|                 return Err(jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                     -32000, |  | ||||||
|                     "Encryption key not found for encrypted database", |  | ||||||
|                     None::<()> |  | ||||||
|                 )); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             String::from_utf8(content) |  | ||||||
|                 .map_err(|_| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                     -32000, |  | ||||||
|                     "Invalid UTF-8 in meta file", |  | ||||||
|                     None::<()> |  | ||||||
|                 ))? |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         serde_json::from_str(&json_str) |         serde_json::from_str(&json_str) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
| @@ -336,7 +300,7 @@ impl RpcServerImpl { | |||||||
|     pub async fn save_meta_static(base_dir: &str, db_id: u64, meta: &DatabaseMeta) -> Result<(), jsonrpsee::types::ErrorObjectOwned> { |     pub async fn save_meta_static(base_dir: &str, db_id: u64, meta: &DatabaseMeta) -> Result<(), jsonrpsee::types::ErrorObjectOwned> { | ||||||
|         let meta_path = std::path::PathBuf::from(base_dir).join(format!("{}_meta.json", db_id)); |         let meta_path = std::path::PathBuf::from(base_dir).join(format!("{}_meta.json", db_id)); | ||||||
|  |  | ||||||
|         let json_str = serde_json::to_string(meta) |         let json_str = serde_json::to_string_pretty(meta) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
|                 format!("Failed to serialize meta: {}", e), |                 format!("Failed to serialize meta: {}", e), | ||||||
| @@ -357,40 +321,20 @@ impl RpcServerImpl { | |||||||
|     async fn save_meta(&self, db_id: u64, meta: &DatabaseMeta) -> Result<(), jsonrpsee::types::ErrorObjectOwned> { |     async fn save_meta(&self, db_id: u64, meta: &DatabaseMeta) -> Result<(), jsonrpsee::types::ErrorObjectOwned> { | ||||||
|         let meta_path = std::path::PathBuf::from(&self.base_dir).join(format!("{}_meta.json", db_id)); |         let meta_path = std::path::PathBuf::from(&self.base_dir).join(format!("{}_meta.json", db_id)); | ||||||
|  |  | ||||||
|         let json_str = serde_json::to_string(meta) |         let json_str = serde_json::to_string_pretty(meta) | ||||||
|             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 -32000, |                 -32000, | ||||||
|                 format!("Failed to serialize meta: {}", e), |                 format!("Failed to serialize meta: {}", e), | ||||||
|                 None::<()> |                 None::<()> | ||||||
|             ))?; |             ))?; | ||||||
|  |  | ||||||
|         if db_id >= 10 { |         // Meta files are always stored as plain JSON (even when data DB is encrypted) | ||||||
|             // Encrypted database, encrypt meta |         std::fs::write(&meta_path, json_str) | ||||||
|             if let Some(key) = self.encryption_keys.read().await.get(&db_id).and_then(|k| k.as_ref()) { |             .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( | ||||||
|                 use crate::crypto::CryptoFactory; |                 -32000, | ||||||
|                 let crypto = CryptoFactory::new(key.as_bytes()); |                 format!("Failed to write meta file: {}", e), | ||||||
|                 let encrypted = crypto.encrypt(json_str.as_bytes()); |                 None::<()> | ||||||
|                 std::fs::write(&meta_path, encrypted) |             ))?; | ||||||
|                     .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                         -32000, |  | ||||||
|                         format!("Failed to write encrypted meta file: {}", e), |  | ||||||
|                         None::<()> |  | ||||||
|                     ))?; |  | ||||||
|             } else { |  | ||||||
|                 return Err(jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                     -32000, |  | ||||||
|                     "Encryption key not found for encrypted database", |  | ||||||
|                     None::<()> |  | ||||||
|                 )); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             std::fs::write(&meta_path, json_str) |  | ||||||
|                 .map_err(|e| jsonrpsee::types::ErrorObjectOwned::owned( |  | ||||||
|                     -32000, |  | ||||||
|                     format!("Failed to write meta file: {}", e), |  | ||||||
|                     None::<()> |  | ||||||
|                 ))?; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user