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