use crate::grpc::types::*;
use crate::error::ServerError;
use fortress_core::encryption::{Aegis256, EncryptionAlgorithm};
use fortress_core::key::{SecureKey, KeyManager};
use fortress_core::error::FortressError;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, error, debug, warn};
use hex;
#[derive(Clone)]
pub struct FortressGrpcService {
database: Arc<RwLock<Option<()>>>, encryption_manager: Arc<Aegis256>,
key_manager: Arc<dyn KeyManager>,
}
impl FortressGrpcService {
pub fn new(encryption_manager: Arc<Aegis256>, key_manager: Arc<dyn KeyManager>) -> Self {
Self {
database: Arc::new(RwLock::new(None)),
encryption_manager,
key_manager,
}
}
pub async fn set_database(&self, _database: ()) {
let mut db = self.database.write().await;
*db = Some(()); }
fn map_error(err: ServerError) -> String {
error!("gRPC service error: {:?}", err);
err.to_string()
}
}
impl FortressGrpcService {
pub async fn create_database(
&self,
request: CreateDatabaseRequest,
) -> Result<DatabaseResponse, String> {
info!("Creating database: {}", request.name);
let database = Database {
id: uuid::Uuid::new_v4().to_string(),
name: request.name,
description: request.description,
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
config: request.config.unwrap_or_default(),
};
Ok(DatabaseResponse { database })
}
pub async fn get_database(
&self,
request: GetDatabaseRequest,
) -> Result<DatabaseResponse, String> {
debug!("Getting database: {}", request.database_id);
Err("Database not found".to_string())
}
pub async fn list_databases(
&self,
_request: ListDatabasesRequest,
) -> Result<ListDatabasesResponse, String> {
info!("Listing databases");
Ok(ListDatabasesResponse {
databases: vec![],
next_page_token: "".to_string(),
})
}
pub async fn delete_database(
&self,
request: DeleteDatabaseRequest,
) -> Result<(), String> {
info!("Deleting database: {}", request.database_id);
Ok(())
}
pub async fn encrypt_data(
&self,
request: EncryptRequest,
) -> Result<EncryptResponse, String> {
debug!("Encrypting data for database: {}", request.database_id);
if request.plaintext.is_empty() {
return Err("Data to encrypt cannot be empty".to_string());
}
if request.key_id.as_ref().map_or(true, |s| s.is_empty()) {
return Err("Key ID cannot be empty".to_string());
}
let key_id = request.key_id.clone().unwrap_or_default();
let key = match self.key_manager.retrieve_key(&key_id).await {
Ok(key) => key,
Err(e) => {
error!("Failed to get encryption key: {}", e);
return Err(format!("Key not found: {}", e));
}
};
match self.encryption_manager.encrypt(
&request.plaintext,
key.0.as_bytes(), ) {
Ok(encrypted_data) => {
info!("Successfully encrypted {} bytes for database {}",
request.plaintext.len(), request.database_id);
Ok(EncryptResponse {
ciphertext: encrypted_data,
key_id: key_id,
encrypted_at: chrono::Utc::now(),
metadata: HashMap::new(),
})
}
Err(e) => {
error!("Failed to encrypt data: {}", e);
Err(format!("Encryption failed: {}", e))
}
}
}
pub async fn decrypt_data(
&self,
request: DecryptRequest,
) -> Result<DecryptResponse, String> {
debug!("Decrypting data for database: {}", request.database_id);
if request.ciphertext.is_empty() {
return Err("Encrypted data cannot be empty".to_string());
}
if request.key_id.is_empty() {
return Err("Key ID cannot be empty".to_string());
}
let key = match self.key_manager.retrieve_key(&request.key_id).await {
Ok(key) => key,
Err(e) => {
error!("Failed to get decryption key: {}", e);
return Err(format!("Key not found: {}", e));
}
};
match self.encryption_manager.decrypt(
&request.ciphertext,
key.0.as_bytes(), ) {
Ok(decrypted_data) => {
info!("Successfully decrypted {} bytes for database {}",
decrypted_data.len(), request.database_id);
Ok(DecryptResponse {
plaintext: decrypted_data,
decrypted_at: chrono::Utc::now(),
metadata: HashMap::new(),
})
}
Err(e) => {
error!("Failed to decrypt data: {}", e);
Err(format!("Decryption failed: {}", e))
}
}
}
pub async fn batch_encrypt_data(
&self,
request: BatchEncryptRequest,
) -> Result<BatchEncryptResponse, String> {
debug!("Batch encrypting {} items for database: {}", request.items.len(), request.database_id);
if request.items.is_empty() {
return Err("Items cannot be empty".to_string());
}
let mut results = Vec::new();
let mut errors = Vec::new();
for (index, item) in request.items.into_iter().enumerate() {
let encrypt_request = EncryptRequest {
database_id: request.database_id.clone(),
plaintext: item.data,
key_id: Some(item.key_id.clone()),
metadata: HashMap::new(),
};
match self.encrypt_data(encrypt_request).await {
Ok(response) => {
results.push(BatchEncryptResult {
index: index as u32,
encrypted_data: hex::encode(&response.ciphertext),
algorithm: "aes-256-gcm".to_string(),
key_id: response.key_id,
timestamp: response.encrypted_at,
success: true,
error: None,
});
}
Err(e) => {
errors.push(BatchEncryptError {
index: index as u32,
error: e.clone(),
});
results.push(BatchEncryptResult {
index: index as u32,
encrypted_data: String::new(),
algorithm: String::new(),
key_id: String::new(),
timestamp: chrono::Utc::now(),
success: false,
error: Some(e),
});
}
}
}
info!("Batch encryption completed: {} successful, {} failed",
results.iter().filter(|r| r.success).count(),
errors.len());
Ok(BatchEncryptResponse {
results: results.clone(),
errors: errors.clone(),
total_items: results.len() as u32,
successful_items: results.iter().filter(|r| r.success).count() as u32,
failed_items: errors.len() as u32,
})
}
pub async fn batch_decrypt_data(
&self,
request: BatchDecryptRequest,
) -> Result<BatchDecryptResponse, String> {
debug!("Batch decrypting {} items for database: {}", request.items.len(), request.database_id);
if request.items.is_empty() {
return Err("Items cannot be empty".to_string());
}
let mut results = Vec::new();
let mut errors = Vec::new();
for (index, item) in request.items.into_iter().enumerate() {
let decrypt_request = DecryptRequest {
database_id: request.database_id.clone(),
ciphertext: item.encrypted_data.as_bytes().to_vec(),
key_id: item.key_id.clone(),
};
match self.decrypt_data(decrypt_request).await {
Ok(response) => {
results.push(BatchDecryptResult {
index: index as u32,
data: response.plaintext,
algorithm: "aes-256-gcm".to_string(),
key_id: "".to_string(),
timestamp: response.decrypted_at,
success: true,
error: None,
});
}
Err(e) => {
errors.push(BatchDecryptError {
index: index as u32,
error: e.clone(),
});
results.push(BatchDecryptResult {
index: index as u32,
data: Vec::new(),
algorithm: String::new(),
key_id: String::new(),
timestamp: chrono::Utc::now(),
success: false,
error: Some(e),
});
}
}
}
info!("Batch decryption completed: {} successful, {} failed",
results.iter().filter(|r| r.success).count(),
errors.len());
Ok(BatchDecryptResponse {
results: results.clone(),
errors: errors.clone(),
total_items: results.len() as u32,
successful_items: results.iter().filter(|r| r.success).count() as u32,
failed_items: errors.len() as u32,
})
}
pub async fn health_check(
&self,
) -> Result<HealthResponse, String> {
debug!("Health check requested");
let components = vec![
ComponentHealth {
name: "encryption".to_string(),
status: 1, message: "All encryption systems operational".to_string(),
},
ComponentHealth {
name: "storage".to_string(),
status: 1, message: "Storage backend operational".to_string(),
},
];
let response = HealthResponse {
status: 1, version: "0.1.0".to_string(),
timestamp: chrono::Utc::now(),
components,
};
Ok(response)
}
pub async fn get_metrics(
&self,
) -> Result<MetricsResponse, String> {
debug!("Metrics requested");
let response = MetricsResponse {
timestamp: chrono::Utc::now(),
counters: HashMap::new(),
gauges: HashMap::new(),
histograms: HashMap::new(),
};
Ok(response)
}
}