Skip to main content

merka_vault/
actor.rs

1//! Actor module for the Merka Vault library
2//!
3//! This module implements the Actix-based actor system for the Merka Vault library.
4//! It serves as the core domain layer that coordinates interactions between the API layers
5//! (server, CLI) and the implementation layers (vault, database).
6//!
7//! Architectural role:
8//! - The actor module is the central coordinator for all vault operations
9//! - It manages state and persistence through the database module
10//! - It delegates vault operations to the vault module
11//! - It provides a message-based API for the server and CLI modules
12//!
13//! This design ensures clean separation of concerns and prevents direct access to
14//! implementation details from the API layers.
15
16use actix::prelude::*;
17use async_trait::async_trait;
18use futures_util::FutureExt;
19use reqwest::StatusCode;
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use std::sync::Arc;
23use std::time::{Duration, SystemTime};
24use tokio::sync::broadcast;
25use tokio::time;
26use tracing::{debug, error, info, warn};
27
28use crate::database::{DatabaseManager, VaultCredentials};
29use crate::interface::VaultInterface;
30use crate::vault::common::VaultStatus;
31use crate::vault::init::{InitResult, UnsealResult};
32use crate::vault::setup_root::{setup_root_vault, RootSetupConfig};
33use crate::vault::setup_sub::{setup_sub_vault, SubSetupConfig, SubSetupResult};
34use crate::vault::{AutoUnsealResult, PkiResult, VaultError};
35
36/// Error type for the actor module
37#[derive(Debug, thiserror::Error)]
38pub enum ActorError {
39    #[error("Vault API error: {0}")]
40    VaultApi(String),
41
42    #[error("Network error: {0}")]
43    Network(String),
44
45    #[error("Actor operation failed: {0}")]
46    Operation(String),
47
48    #[error("Actor message handling failed: {0}")]
49    Messaging(String),
50
51    #[error("Timeout: {0}")]
52    Timeout(String),
53
54    #[error("HTTP error: {0}")]
55    HttpError(String),
56}
57
58/// Add conversion from VaultError to ActorError
59impl From<VaultError> for ActorError {
60    fn from(error: VaultError) -> Self {
61        match error {
62            VaultError::Api(msg) => ActorError::VaultApi(msg),
63            VaultError::ApiError(msg) => ActorError::VaultApi(msg),
64            VaultError::Network(msg) => ActorError::Network(msg),
65            VaultError::Connection(msg) => ActorError::Network(msg),
66            VaultError::ParseError(msg) => ActorError::VaultApi(format!("Parse error: {}", msg)),
67            VaultError::Parsing(msg) => ActorError::VaultApi(format!("Parsing error: {}", msg)),
68            VaultError::HttpStatus(code, msg) => {
69                ActorError::VaultApi(format!("HTTP {}: {}", code, msg))
70            }
71            VaultError::AlreadyInitialized => {
72                ActorError::VaultApi("Vault is already initialized".to_string())
73            }
74            VaultError::Sealed(msg) => ActorError::VaultApi(format!("Vault is sealed: {}", msg)),
75            VaultError::RequestError(msg) => ActorError::Network(format!("Request error: {}", msg)),
76            VaultError::Reqwest(err) => ActorError::Network(format!("Reqwest error: {}", err)),
77            VaultError::Json(err) => ActorError::VaultApi(format!("JSON error: {}", err)),
78        }
79    }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct VaultHealth {
84    pub addr: String,
85    pub initialized: bool,
86    pub sealed: bool,
87    pub standby: bool,
88    pub last_check: SystemTime,
89    pub is_auto_unsealed: bool,
90    pub unsealer_addr: Option<String>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub enum VaultEvent {
95    Initialized {
96        root_token: String,
97        keys: Vec<String>,
98    },
99    Unsealed {
100        progress: u8,
101        threshold: u8,
102        sealed: bool,
103    },
104    PkiSetupComplete {
105        role_name: String,
106        cert_chain: String,
107    },
108    AutounsealComplete {
109        root_token: String,
110        recovery_keys: Option<Vec<String>>,
111    },
112    StatusChecked {
113        initialized: bool,
114        sealed: bool,
115        standby: bool,
116    },
117    // Note: This used to be for single-step multi-tier. Remove or rename.
118    SetupComplete {
119        root_token: String,
120        root_role: String,
121        sub_token: String,
122        int_role: String,
123    },
124    Error(String),
125    VaultHealthUpdated {
126        addr: String,
127        health: VaultHealth,
128    },
129    VaultsListed {
130        vaults: Vec<VaultHealth>,
131    },
132    TransitTokenUnwrapped {
133        root_addr: String,
134        unwrapped_token: String,
135    },
136    TokenVerified {
137        valid: bool,
138        message: String,
139    },
140    TransitSetup {
141        success: bool,
142        key_name: String,
143    },
144    AutoUnsealDependencyError {
145        sub_addr: String,
146        root_addr: String,
147        error: String,
148    },
149}
150
151/// Public struct containing vault status information
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct StatusInfo {
154    pub initialized: bool,
155    pub sealed: bool,
156    pub standby: bool,
157}
158
159impl From<VaultStatus> for StatusInfo {
160    fn from(status: VaultStatus) -> Self {
161        Self {
162            initialized: status.initialized,
163            sealed: status.sealed,
164            standby: status.standby,
165        }
166    }
167}
168
169#[derive(Clone)]
170pub struct VaultActor {
171    pub vault_addr: String,
172    pub root_token: Option<String>,
173    pub event_sender: Option<broadcast::Sender<VaultEvent>>,
174    pub known_vaults: HashMap<String, VaultHealth>,
175    pub unsealer_relationships: HashMap<String, String>,
176    pub db_manager: Option<Arc<DatabaseManager>>,
177}
178
179impl VaultActor {
180    pub fn new<S: Into<String>>(
181        vault_addr: S,
182        event_sender: Option<broadcast::Sender<VaultEvent>>,
183    ) -> Self {
184        Self {
185            vault_addr: vault_addr.into(),
186            root_token: None,
187            event_sender,
188            known_vaults: HashMap::new(),
189            unsealer_relationships: HashMap::new(),
190            db_manager: None,
191        }
192    }
193
194    /// Creates a VaultActor with a test configuration
195    pub fn new_with_test_config<S: Into<String>>(
196        vault_addr: S,
197        event_sender: Option<broadcast::Sender<VaultEvent>>,
198    ) -> Self {
199        Self {
200            vault_addr: vault_addr.into(),
201            root_token: None,
202            event_sender,
203            known_vaults: HashMap::new(),
204            unsealer_relationships: HashMap::new(),
205            db_manager: None,
206        }
207    }
208
209    /// Set the database manager for persistent storage
210    pub fn with_database(mut self, db_manager: DatabaseManager) -> Self {
211        self.db_manager = Some(Arc::new(db_manager));
212
213        // Try to load vault credentials from the database if we don't have a token yet
214        if self.root_token.is_none() && self.db_manager.is_some() {
215            if let Some(db) = &self.db_manager {
216                match db.load_vault_credentials() {
217                    Ok(credentials) => {
218                        if !credentials.root_token.is_empty() {
219                            info!(
220                                "Loaded root token from database for vault {}",
221                                self.vault_addr
222                            );
223                            self.root_token = Some(credentials.root_token);
224                        } else {
225                            warn!(
226                                "Root token in database is empty for vault {}",
227                                self.vault_addr
228                            );
229                        }
230                    }
231                    Err(e) => {
232                        warn!("Failed to load credentials from database: {}", e);
233                    }
234                }
235            }
236        }
237
238        // Also load unsealer relationships
239        if let Some(db) = &self.db_manager {
240            match db.load_unsealer_relationships() {
241                Ok(relationships) => {
242                    info!(
243                        "Loaded {} unsealer relationships from database",
244                        relationships.len()
245                    );
246                    self.unsealer_relationships = relationships;
247                }
248                Err(e) => {
249                    warn!("Failed to load unsealer relationships from database: {}", e);
250                }
251            }
252        }
253
254        self
255    }
256
257    pub async fn start_monitoring(&mut self) {
258        let mut interval = time::interval(Duration::from_secs(30));
259
260        // Register the primary vault
261        self.register_vault(self.vault_addr.clone()).await;
262
263        // Start the monitoring loop
264        loop {
265            interval.tick().await;
266
267            // In each cycle, check all known vaults
268            let addrs: Vec<String> = self.known_vaults.keys().cloned().collect();
269            for addr in addrs {
270                self.register_vault(addr).await;
271            }
272
273            // After checking the vaults, verify their relationships
274            self.check_auto_unseal_dependencies().await;
275        }
276    }
277
278    // Method to check auto-unseal dependencies
279    async fn check_auto_unseal_dependencies(&mut self) {
280        // Add debug logging for the current state
281        debug!("Checking auto-unseal dependencies. Current state:");
282        debug!(
283            "Known vaults: {:?}",
284            self.known_vaults.keys().collect::<Vec<_>>()
285        );
286        debug!("Unsealer relationships: {:?}", self.unsealer_relationships);
287
288        // For each relationship, check if root vault is sealed or not initialized
289        for (sub_addr, root_addr) in self.unsealer_relationships.clone() {
290            // First refresh the vault statuses
291            if let Ok(root_status) = self.check_status(&root_addr).await {
292                if let Ok(sub_status) = self.check_status(&sub_addr).await {
293                    // Update the known_vaults map with fresh statuses
294                    let mut root_health = self
295                        .known_vaults
296                        .get(&root_addr)
297                        .cloned()
298                        .unwrap_or_else(|| VaultHealth {
299                            addr: root_addr.clone(),
300                            initialized: root_status.initialized,
301                            sealed: root_status.sealed,
302                            standby: root_status.standby,
303                            last_check: SystemTime::now(),
304                            is_auto_unsealed: false,
305                            unsealer_addr: None,
306                        });
307
308                    // Update with fresh status
309                    root_health.initialized = root_status.initialized;
310                    root_health.sealed = root_status.sealed;
311                    root_health.standby = root_status.standby;
312                    root_health.last_check = SystemTime::now();
313
314                    // Same for sub vault
315                    let mut sub_health =
316                        self.known_vaults
317                            .get(&sub_addr)
318                            .cloned()
319                            .unwrap_or_else(|| VaultHealth {
320                                addr: sub_addr.clone(),
321                                initialized: sub_status.initialized,
322                                sealed: sub_status.sealed,
323                                standby: sub_status.standby,
324                                last_check: SystemTime::now(),
325                                is_auto_unsealed: true,
326                                unsealer_addr: Some(root_addr.clone()),
327                            });
328
329                    // Update with fresh status
330                    sub_health.initialized = sub_status.initialized;
331                    sub_health.sealed = sub_status.sealed;
332                    sub_health.standby = sub_status.standby;
333                    sub_health.last_check = SystemTime::now();
334
335                    // Update the maps
336                    self.known_vaults
337                        .insert(root_addr.clone(), root_health.clone());
338                    self.known_vaults
339                        .insert(sub_addr.clone(), sub_health.clone());
340
341                    // Log statuses for debugging
342                    debug!(
343                        "Checking auto-unseal dependency: root={} (sealed={}, init={}), sub={} (sealed={}, init={})",
344                        root_addr, root_health.sealed, root_health.initialized,
345                        sub_addr, sub_health.sealed, sub_health.initialized
346                    );
347
348                    // The critical condition is if the root vault is sealed or not initialized
349                    if root_health.sealed || !root_health.initialized {
350                        let error_msg = if root_health.sealed {
351                            format!(
352                                "Sub vault at {} cannot auto-unseal because root vault at {} is sealed",
353                                sub_addr, root_addr
354                            )
355                        } else if !root_health.initialized {
356                            format!("Sub vault at {} cannot auto-unseal because root vault at {} is not initialized", sub_addr, root_addr)
357                        } else {
358                            format!(
359                                "Sub vault at {} cannot auto-unseal due to issues with root vault at {}",
360                                sub_addr, root_addr
361                            )
362                        };
363
364                        debug!("Auto-unseal dependency error detected: {}", error_msg);
365
366                        // Emit an event for this error condition
367                        if let Some(sender) = &self.event_sender {
368                            debug!(
369                                "Sending AutoUnsealDependencyError event for sub={}, root={}",
370                                sub_addr, root_addr
371                            );
372                            let send_result = sender.send(VaultEvent::AutoUnsealDependencyError {
373                                sub_addr: sub_addr.clone(),
374                                root_addr: root_addr.clone(),
375                                error: error_msg.clone(),
376                            });
377
378                            if let Err(e) = &send_result {
379                                debug!("Failed to send AutoUnsealDependencyError event: {}", e);
380                            } else {
381                                debug!("Successfully sent AutoUnsealDependencyError event");
382                            }
383
384                            // Also send a general error for backwards compatibility
385                            let general_result = sender.send(VaultEvent::Error(error_msg));
386                            if let Err(e) = &general_result {
387                                debug!("Failed to send Error event: {}", e);
388                            }
389                        } else {
390                            warn!(
391                                "No event sender available to send AutoUnsealDependencyError event"
392                            );
393                        }
394                    } else {
395                        debug!(
396                            "No dependency issues detected between root={} and sub={}",
397                            root_addr, sub_addr
398                        );
399                    }
400                } else {
401                    warn!("Failed to check status for sub vault at {}", sub_addr);
402                }
403            } else {
404                warn!("Failed to check status for root vault at {}", root_addr);
405            }
406        }
407    }
408
409    async fn register_vault(&mut self, addr: String) {
410        let should_check_config = !self.known_vaults.contains_key(&addr);
411
412        if let Ok(status) = self.check_status(&addr).await {
413            // Detect if this is an auto-unsealed vault by checking its configuration
414            let is_auto_unsealed = should_check_config && self.check_is_auto_unsealed(&addr).await;
415            let unsealer_addr = if is_auto_unsealed {
416                let root_addr = self.get_unsealer_address(&addr).await;
417                if let Some(root) = &root_addr {
418                    // Register the relationship for dependency checking
419                    self.unsealer_relationships
420                        .insert(addr.clone(), root.clone());
421                }
422                root_addr
423            } else {
424                None
425            };
426
427            let health = VaultHealth {
428                addr: addr.clone(),
429                initialized: status.initialized,
430                sealed: status.sealed,
431                standby: status.standby,
432                last_check: SystemTime::now(),
433                is_auto_unsealed,
434                unsealer_addr,
435            };
436
437            // Update in-memory cache
438            self.known_vaults.insert(addr.clone(), health.clone());
439
440            // Emit event
441            if let Some(sender) = &self.event_sender {
442                let _ = sender.send(VaultEvent::VaultHealthUpdated {
443                    addr: addr.clone(),
444                    health,
445                });
446            }
447        }
448    }
449
450    // New helper method to check if a vault is using auto-unseal
451    async fn check_is_auto_unsealed(&self, addr: &str) -> bool {
452        // Try to retrieve the seal configuration to determine if transit seal is being used
453        let client = reqwest::Client::new();
454        let url = format!("{}/v1/sys/seal-status", addr);
455
456        if let Ok(resp) = client.get(&url).send().await {
457            if resp.status().is_success() {
458                // Parse the response to check seal type
459                if let Ok(json) = resp.json::<serde_json::Value>().await {
460                    if let Some(seal_type) = json.get("type") {
461                        // If seal type is "transit", this is an auto-unsealed vault
462                        return seal_type.as_str().unwrap_or("").contains("transit");
463                    }
464                }
465            }
466        }
467
468        false
469    }
470
471    // New helper method to get the unsealer address for a sub vault
472    async fn get_unsealer_address(&self, addr: &str) -> Option<String> {
473        // Try to get the configuration which should include the transit seal details
474        let client = reqwest::Client::new();
475        let url = format!("{}/v1/sys/config/state/sanitized", addr);
476
477        // Note: This endpoint requires high privileges and may not be accessible
478        // For real implementations, we might need to store this relationship when setting up
479        // In this example, we'll fall back to checking the config if accessible,
480        // or infer from seal type and relationships we observe
481
482        if let Ok(resp) = client.get(&url).send().await {
483            if resp.status().is_success() {
484                if let Ok(json) = resp.json::<serde_json::Value>().await {
485                    if let Some(seal) = json.get("seal") {
486                        if let Some(config) = seal.get("config") {
487                            if let Some(address) = config.get("address") {
488                                return address.as_str().map(|s| s.to_string());
489                            }
490                        }
491                    }
492                }
493            }
494        }
495
496        // If we couldn't get the config, check if we've already tracked this relationship elsewhere
497        // In a real implementation, this would be stored when setting up the auto-unseal relationship
498        None
499    }
500
501    // Add a method to manually trigger the dependency check
502    pub async fn check_dependencies_now(&mut self) {
503        // First update status of all known vaults
504        let addrs: Vec<String> = self.known_vaults.keys().cloned().collect();
505        for addr in addrs {
506            self.register_vault(addr).await;
507        }
508
509        // Then run the dependency check
510        self.check_auto_unseal_dependencies().await;
511    }
512
513    /// Verifies if a token is valid for the current vault
514    pub async fn verify_token(&self, token: &str) -> Result<bool, VaultError> {
515        let client = reqwest::Client::new();
516        let url = format!("{}/v1/auth/token/lookup-self", self.vault_addr);
517
518        let response = client
519            .get(&url)
520            .header("X-Vault-Token", token)
521            .send()
522            .await
523            .map_err(|e| VaultError::Network(format!("Network error: {}", e)))?;
524
525        // If status is successful, token is valid
526        if response.status().is_success() {
527            return Ok(true);
528        }
529
530        // Otherwise token is invalid
531        Ok(false)
532    }
533}
534
535impl Actor for VaultActor {
536    type Context = Context<Self>;
537}
538
539/// Optional trait that you can use if you want to unify common Vault tasks
540#[async_trait]
541pub trait VaultOperations {
542    /// Initialize a new Vault instance
543    async fn initialize(
544        &mut self,
545        secret_shares: u8,
546        secret_threshold: u8,
547    ) -> Result<InitResult, VaultError>;
548
549    /// Unseal a vault with key shares
550    async fn unseal(&mut self, keys: Vec<String>) -> Result<UnsealResult, VaultError>;
551
552    /// Check Vault status
553    async fn status(&self) -> Result<VaultStatus, VaultError>;
554
555    /// Setup PKI infrastructure
556    async fn setup_pki(&mut self, role_name: String) -> Result<PkiResult, VaultError>;
557
558    /// Perform auto-unsealing
559    async fn auto_unseal(
560        &mut self,
561        recovery_shares: Option<u8>,
562    ) -> Result<AutoUnsealResult, VaultError>;
563
564    // Removed the old single-step `setup_multi_tier` to avoid the "could not find setup" error
565}
566
567#[async_trait]
568impl VaultOperations for VaultActor {
569    async fn initialize(
570        &mut self,
571        secret_shares: u8,
572        secret_threshold: u8,
573    ) -> Result<InitResult, VaultError> {
574        let addr = self.vault_addr.clone();
575        let event_sender = self.event_sender.clone();
576
577        match crate::vault::init::init_vault(&addr, secret_shares, secret_threshold, None, None)
578            .await
579        {
580            Ok(init_resp) => {
581                if let Some(sender) = &event_sender {
582                    let _ = sender.send(VaultEvent::Initialized {
583                        root_token: init_resp.root_token.clone(),
584                        keys: init_resp.keys.clone(),
585                    });
586                }
587                self.root_token = Some(init_resp.root_token.clone());
588                Ok(init_resp)
589            }
590            Err(err) => {
591                if let Some(sender) = &event_sender {
592                    let _ = sender.send(VaultEvent::Error(format!("{}", err)));
593                }
594                Err(VaultError::Api(format!("Initialization error: {}", err)))
595            }
596        }
597    }
598
599    async fn unseal(&mut self, keys: Vec<String>) -> Result<UnsealResult, VaultError> {
600        let addr = self.vault_addr.clone();
601        let event_sender = self.event_sender.clone();
602
603        match crate::vault::init::unseal_root_vault(&addr, keys).await {
604            Ok(unseal_resp) => {
605                if let Some(sender) = &event_sender {
606                    let _ = sender.send(VaultEvent::Unsealed {
607                        progress: unseal_resp.progress,
608                        threshold: unseal_resp.threshold,
609                        sealed: unseal_resp.sealed,
610                    });
611                }
612                Ok(unseal_resp)
613            }
614            Err(err) => {
615                if let Some(sender) = &event_sender {
616                    let _ = sender.send(VaultEvent::Error(format!("{}", err)));
617                }
618                Err(VaultError::Api(format!("Unseal error: {}", err)))
619            }
620        }
621    }
622
623    async fn status(&self) -> Result<VaultStatus, VaultError> {
624        let addr = self.vault_addr.clone();
625        let event_sender = self.event_sender.clone();
626
627        match crate::vault::common::check_vault_status(&addr).await {
628            Ok(status) => {
629                if let Some(sender) = &event_sender {
630                    let _ = sender.send(VaultEvent::StatusChecked {
631                        initialized: status.initialized,
632                        sealed: status.sealed,
633                        standby: status.standby,
634                    });
635                }
636                Ok(status)
637            }
638            Err(err) => {
639                if let Some(sender) = &event_sender {
640                    let _ = sender.send(VaultEvent::Error(format!("{}", err)));
641                }
642                Err(VaultError::Api(format!("Status check error: {}", err)))
643            }
644        }
645    }
646
647    async fn setup_pki(&mut self, role_name: String) -> Result<PkiResult, VaultError> {
648        let addr = self.vault_addr.clone();
649        let event_sender = self.event_sender.clone();
650        let token = self.root_token.clone().unwrap_or_default();
651
652        // For demonstration: a simple root PKI (no intermediate)
653        let common_name = role_name.clone();
654        let ttl = "8760h";
655        let intermediate = false;
656        let intermediate_addr = None;
657        let int_token = None;
658
659        match crate::vault::pki::setup_pki(
660            &addr,
661            &token,
662            &common_name,
663            ttl,
664            intermediate,
665            intermediate_addr,
666            int_token,
667        )
668        .await
669        {
670            Ok((cert_chain, role)) => {
671                let result = PkiResult {
672                    cert_chain,
673                    role_name: role,
674                };
675
676                if let Some(sender) = &event_sender {
677                    let _ = sender.send(VaultEvent::PkiSetupComplete {
678                        role_name: result.role_name.clone(),
679                        cert_chain: result.cert_chain.clone(),
680                    });
681                }
682                Ok(result)
683            }
684            Err(err) => {
685                if let Some(sender) = &event_sender {
686                    let _ = sender.send(VaultEvent::Error(format!("{}", err)));
687                }
688                Err(VaultError::Api(format!("PKI setup error: {}", err)))
689            }
690        }
691    }
692
693    async fn auto_unseal(
694        &mut self,
695        _recovery_shares: Option<u8>,
696    ) -> Result<AutoUnsealResult, VaultError> {
697        let addr = self.vault_addr.clone();
698        let event_sender = self.event_sender.clone();
699
700        match crate::vault::autounseal::init_with_autounseal(&addr).await {
701            Ok(init_result) => {
702                let auto_result = AutoUnsealResult {
703                    root_token: init_result.root_token.clone(),
704                    recovery_keys: init_result.recovery_keys.clone(),
705                    success: true,
706                };
707
708                if let Some(sender) = &event_sender {
709                    let _ = sender.send(VaultEvent::AutounsealComplete {
710                        root_token: auto_result.root_token.clone(),
711                        recovery_keys: auto_result.recovery_keys.clone(),
712                    });
713                }
714
715                // Save the new root token
716                self.root_token = Some(init_result.root_token);
717                Ok(auto_result)
718            }
719            Err(err) => {
720                if let Some(sender) = &event_sender {
721                    let _ = sender.send(VaultEvent::Error(format!("{}", err)));
722                }
723                Err(VaultError::Api(format!("Auto-unseal error: {}", err)))
724            }
725        }
726    }
727}
728
729// -----------------------------------------------------------------------------
730// Actor messages & handlers
731// -----------------------------------------------------------------------------
732
733/// Message for initializing a Vault with shares & threshold
734#[derive(Message, Debug, Clone)]
735#[rtype(result = "Result<InitResult, ActorError>")]
736pub struct InitVault {
737    pub secret_shares: u8,
738    pub secret_threshold: u8,
739}
740
741impl Handler<InitVault> for VaultActor {
742    type Result = ResponseFuture<Result<InitResult, ActorError>>;
743
744    fn handle(&mut self, msg: InitVault, _ctx: &mut Context<Self>) -> Self::Result {
745        let mut actor = self.clone();
746        async move {
747            actor
748                .initialize(msg.secret_shares, msg.secret_threshold)
749                .await
750                .map_err(ActorError::from)
751        }
752        .boxed_local()
753    }
754}
755
756/// Message for unsealing a Vault
757#[derive(Message, Debug, Clone)]
758#[rtype(result = "Result<UnsealResult, ActorError>")]
759pub struct UnsealVault {
760    pub keys: Vec<String>,
761}
762
763impl Handler<UnsealVault> for VaultActor {
764    type Result = ResponseFuture<Result<UnsealResult, ActorError>>;
765
766    fn handle(&mut self, msg: UnsealVault, _ctx: &mut Context<Self>) -> Self::Result {
767        let actor = self.clone();
768        let addr = actor.vault_addr.clone();
769        async move {
770            actor
771                .unseal(&addr, msg.keys)
772                .await
773                .map_err(ActorError::from)
774        }
775        .boxed_local()
776    }
777}
778
779/// Message for checking status
780#[derive(Message, Debug, Clone)]
781#[rtype(result = "Result<StatusInfo, ActorError>")]
782pub struct CheckStatus;
783
784impl Handler<CheckStatus> for VaultActor {
785    type Result = ResponseFuture<Result<StatusInfo, ActorError>>;
786
787    fn handle(&mut self, _: CheckStatus, _ctx: &mut Context<Self>) -> Self::Result {
788        let _addr = self.vault_addr.clone();
789        let actor = self.clone();
790        Box::pin(async move {
791            match actor.status().await {
792                Ok(status) => Ok(StatusInfo::from(status)),
793                Err(e) => Err(e.into()),
794            }
795        })
796    }
797}
798
799/// Message for simple PKI
800#[derive(Message, Debug, Clone)]
801#[rtype(result = "Result<PkiResult, ActorError>")]
802pub struct SetupPki {
803    pub role_name: String,
804}
805
806impl Handler<SetupPki> for VaultActor {
807    type Result = ResponseFuture<Result<PkiResult, ActorError>>;
808
809    fn handle(&mut self, msg: SetupPki, _ctx: &mut Context<Self>) -> Self::Result {
810        let mut actor = self.clone();
811        async move {
812            actor
813                .setup_pki(msg.role_name)
814                .await
815                .map_err(ActorError::from)
816        }
817        .boxed_local()
818    }
819}
820
821/// Message for auto-unseal
822#[derive(Message, Debug, Clone)]
823#[rtype(result = "Result<AutoUnsealResult, ActorError>")]
824pub struct AutoUnseal;
825
826impl Handler<AutoUnseal> for VaultActor {
827    type Result = ResponseFuture<Result<AutoUnsealResult, ActorError>>;
828
829    fn handle(&mut self, _msg: AutoUnseal, _ctx: &mut Context<Self>) -> Self::Result {
830        let mut actor = self.clone();
831        async move { actor.auto_unseal(None).await.map_err(ActorError::from) }.boxed_local()
832    }
833}
834
835// Add new messages for setup operations
836#[derive(Message, Debug, Clone)]
837#[rtype(result = "Result<String, ActorError>")]
838pub struct SetupRoot {
839    pub addr: String,
840    pub secret_shares: u8,
841    pub secret_threshold: u8,
842    pub key_name: String,
843}
844
845#[derive(Message, Debug, Clone)]
846#[rtype(result = "Result<String, ActorError>")]
847pub struct SetupSub {
848    pub root_addr: String,
849    pub root_token: String,
850    pub sub_addr: String,
851    pub domain: String,
852    pub ttl: String,
853}
854
855impl Handler<SetupRoot> for VaultActor {
856    type Result = ResponseFuture<Result<String, ActorError>>;
857
858    fn handle(&mut self, msg: SetupRoot, _ctx: &mut Context<Self>) -> Self::Result {
859        let mut actor = self.clone();
860        async move {
861            // Register the root vault
862            actor.register_vault(msg.addr.clone()).await;
863
864            let config = RootSetupConfig {
865                root_addr: msg.addr.clone(),
866                secret_shares: msg.secret_shares,
867                secret_threshold: msg.secret_threshold,
868                key_name: msg.key_name.clone(),
869                mode: "local".to_string(),
870                output_file: None,
871            };
872
873            match setup_root_vault(config).await {
874                Ok(result) => {
875                    // Trigger event, if sender exists
876                    if let Some(sender) = &actor.event_sender {
877                        let _ = sender.send(VaultEvent::Initialized {
878                            root_token: result.root_init.root_token.clone(),
879                            keys: result.root_init.keys.clone(),
880                        });
881                    }
882
883                    // Here, we return the unwrapped token for auto-unseal
884                    Ok(result.unwrapped_token)
885                }
886                Err(e) => Err(ActorError::VaultApi(format!("Root setup error: {}", e))),
887            }
888        }
889        .boxed_local()
890    }
891}
892
893impl Handler<SetupSub> for VaultActor {
894    type Result = ResponseFuture<Result<String, ActorError>>;
895
896    fn handle(&mut self, msg: SetupSub, _ctx: &mut Context<Self>) -> Self::Result {
897        let mut actor = self.clone();
898        async move {
899            // Register both root and sub vaults
900            actor.register_vault(msg.root_addr.clone()).await;
901            actor.register_vault(msg.sub_addr.clone()).await;
902
903            // Register the auto-unseal relationship for monitoring
904            actor
905                .unsealer_relationships
906                .insert(msg.sub_addr.clone(), msg.root_addr.clone());
907
908            let config = SubSetupConfig {
909                sub_addr: msg.sub_addr.clone(),
910                domain: msg.domain,
911                ttl: msg.ttl,
912                root_addr: msg.root_addr.clone(),
913                root_token: msg.root_token,
914            };
915
916            match setup_sub_vault(config).await {
917                Ok(SubSetupResult {
918                    sub_init,
919                    pki_roles,
920                }) => {
921                    let int_role = pki_roles.1.clone();
922                    if let Some(sender) = &actor.event_sender {
923                        let _ = sender.send(VaultEvent::SetupComplete {
924                            root_token: sub_init.root_token.clone(),
925                            root_role: pki_roles.0.clone(),
926                            sub_token: sub_init.root_token,
927                            int_role: pki_roles.1.clone(),
928                        });
929                    }
930                    Ok(int_role)
931                }
932                Err(e) => Err(ActorError::VaultApi(format!("Sub setup error: {}", e))),
933            }
934        }
935        .boxed_local()
936    }
937}
938
939// Add new message type for getting an unwrapped transit token
940#[derive(Message, Debug, Clone)]
941#[rtype(result = "Result<String, ActorError>")]
942pub struct GetUnwrappedTransitToken {
943    pub root_addr: String,
944    pub root_token: String,
945    pub key_name: String,
946}
947
948impl Handler<GetUnwrappedTransitToken> for VaultActor {
949    type Result = ResponseFuture<Result<String, ActorError>>;
950
951    fn handle(&mut self, msg: GetUnwrappedTransitToken, _ctx: &mut Context<Self>) -> Self::Result {
952        let actor = self.clone();
953        async move {
954            debug!(
955                "Getting unwrapped transit token from root vault at {}",
956                msg.root_addr
957            );
958
959            // First, ensure transit auto-unseal is set up
960            if let Err(e) = crate::vault::autounseal::setup_transit_autounseal(
961                &msg.root_addr,
962                &msg.root_token,
963                &msg.key_name,
964            )
965            .await
966            {
967                return Err(ActorError::VaultApi(format!(
968                    "Failed to setup transit auto-unseal: {}",
969                    e
970                )));
971            }
972
973            // Generate a wrapped transit token
974            let wrap_ttl = "300s";
975            let wrapped_token = match crate::vault::transit::generate_wrapped_transit_token(
976                &msg.root_addr,
977                &msg.root_token,
978                "autounseal", // policy name used in setup_transit_autounseal
979                wrap_ttl,
980            )
981            .await
982            {
983                Ok(token) => token,
984                Err(e) => {
985                    return Err(ActorError::VaultApi(format!(
986                        "Failed to generate wrapped token: {}",
987                        e
988                    )))
989                }
990            };
991
992            // Unwrap the token
993            let unwrapped_token = match crate::vault::autounseal::unwrap_token(
994                &msg.root_addr,
995                &wrapped_token,
996            )
997            .await
998            {
999                Ok(token) => token,
1000                Err(e) => {
1001                    return Err(ActorError::VaultApi(format!(
1002                        "Failed to unwrap token: {}",
1003                        e
1004                    )))
1005                }
1006            };
1007
1008            debug!("Successfully obtained unwrapped transit token");
1009
1010            // Emit event if sender is available
1011            if let Some(sender) = &actor.event_sender {
1012                let _ = sender.send(VaultEvent::TransitTokenUnwrapped {
1013                    root_addr: msg.root_addr,
1014                    unwrapped_token: unwrapped_token.clone(),
1015                });
1016            }
1017
1018            Ok(unwrapped_token)
1019        }
1020        .boxed_local()
1021    }
1022}
1023
1024// Add these new message types after the existing actor message definitions
1025
1026/// Message for setting up transit auto-unseal
1027#[derive(Message, Debug, Clone)]
1028#[rtype(result = "Result<String, ActorError>")]
1029pub struct SetupTransit {
1030    pub token: String,
1031    pub key_name: String,
1032}
1033
1034impl Handler<SetupTransit> for VaultActor {
1035    type Result = ResponseFuture<Result<String, ActorError>>;
1036
1037    fn handle(&mut self, msg: SetupTransit, _ctx: &mut Context<Self>) -> Self::Result {
1038        let actor = self.clone();
1039        let addr = actor.vault_addr.clone();
1040
1041        async move {
1042            match crate::vault::autounseal::setup_transit_autounseal(
1043                &addr,
1044                &msg.token,
1045                &msg.key_name,
1046            )
1047            .await
1048            {
1049                Ok(_result) => {
1050                    if let Some(sender) = &actor.event_sender {
1051                        let _ = sender.send(VaultEvent::TransitSetup {
1052                            success: true,
1053                            key_name: msg.key_name.clone(),
1054                        });
1055                    }
1056                    Ok(msg.key_name)
1057                }
1058                Err(e) => {
1059                    if let Some(sender) = &actor.event_sender {
1060                        let _ =
1061                            sender.send(VaultEvent::Error(format!("Transit setup error: {}", e)));
1062                    }
1063                    Err(ActorError::from(e))
1064                }
1065            }
1066        }
1067        .boxed_local()
1068    }
1069}
1070
1071/// Message for generating a wrapped transit token
1072#[derive(Message, Debug, Clone)]
1073#[rtype(result = "Result<String, ActorError>")]
1074pub struct GenerateWrappedToken {
1075    pub policy_name: String,
1076    pub wrap_ttl: String,
1077    pub token: String,
1078}
1079
1080impl Handler<GenerateWrappedToken> for VaultActor {
1081    type Result = ResponseFuture<Result<String, ActorError>>;
1082
1083    fn handle(&mut self, msg: GenerateWrappedToken, _ctx: &mut Context<Self>) -> Self::Result {
1084        let actor = self.clone();
1085        let addr = actor.vault_addr.clone();
1086
1087        async move {
1088            match crate::vault::transit::generate_wrapped_transit_token(
1089                &addr,
1090                &msg.token,
1091                &msg.policy_name,
1092                &msg.wrap_ttl,
1093            )
1094            .await
1095            {
1096                Ok(wrapped_token) => Ok(wrapped_token),
1097                Err(e) => {
1098                    if let Some(sender) = &actor.event_sender {
1099                        let _ = sender.send(VaultEvent::Error(format!(
1100                            "Wrapped token generation error: {}",
1101                            e
1102                        )));
1103                    }
1104                    Err(ActorError::from(e))
1105                }
1106            }
1107        }
1108        .boxed_local()
1109    }
1110}
1111
1112/// Message for unwrapping a token
1113#[derive(Message, Debug, Clone)]
1114#[rtype(result = "Result<String, ActorError>")]
1115pub struct UnwrapToken {
1116    pub wrapped_token: String,
1117}
1118
1119impl Handler<UnwrapToken> for VaultActor {
1120    type Result = ResponseFuture<Result<String, ActorError>>;
1121
1122    fn handle(&mut self, msg: UnwrapToken, _ctx: &mut Context<Self>) -> Self::Result {
1123        let actor = self.clone();
1124        let addr = actor.vault_addr.clone();
1125
1126        async move {
1127            match crate::vault::autounseal::unwrap_token(&addr, &msg.wrapped_token).await {
1128                Ok(unwrapped_token) => {
1129                    if let Some(sender) = &actor.event_sender {
1130                        let _ = sender.send(VaultEvent::TransitTokenUnwrapped {
1131                            root_addr: addr.clone(),
1132                            unwrapped_token: unwrapped_token.clone(),
1133                        });
1134                    }
1135                    Ok(unwrapped_token)
1136                }
1137                Err(e) => {
1138                    if let Some(sender) = &actor.event_sender {
1139                        let _ =
1140                            sender.send(VaultEvent::Error(format!("Token unwrap error: {}", e)));
1141                    }
1142                    Err(ActorError::from(e))
1143                }
1144            }
1145        }
1146        .boxed_local()
1147    }
1148}
1149
1150/// Message for verifying token permissions
1151#[derive(Message, Debug, Clone)]
1152#[rtype(result = "Result<bool, ActorError>")]
1153pub struct VerifyTokenPermissions {
1154    pub token: String,
1155    pub key_name: String,
1156}
1157
1158impl Handler<VerifyTokenPermissions> for VaultActor {
1159    type Result = ResponseFuture<Result<bool, ActorError>>;
1160
1161    fn handle(&mut self, msg: VerifyTokenPermissions, _: &mut Context<Self>) -> Self::Result {
1162        let actor = self.clone();
1163        let addr = actor.vault_addr.clone();
1164
1165        Box::pin(async move {
1166            // If key_name is empty, just verify the token is valid
1167            if msg.key_name.is_empty() {
1168                match actor.verify_token(&msg.token).await {
1169                    Ok(valid) => {
1170                        if let Some(sender) = &actor.event_sender {
1171                            let _ = sender.send(VaultEvent::TokenVerified {
1172                                valid,
1173                                message: if valid {
1174                                    "Token is valid".into()
1175                                } else {
1176                                    "Token is invalid".into()
1177                                },
1178                            });
1179                        }
1180                        return Ok(valid);
1181                    }
1182                    Err(e) => {
1183                        if let Some(sender) = &actor.event_sender {
1184                            let _ = sender.send(VaultEvent::TokenVerified {
1185                                valid: false,
1186                                message: format!("Token verification failed: {}", e),
1187                            });
1188                        }
1189                        return Err(ActorError::from(e));
1190                    }
1191                }
1192            }
1193
1194            // If key_name is specified, verify the token has transit permissions
1195            // Try a simple encryption operation to verify the token has the correct permissions
1196            let client = reqwest::Client::new();
1197            let encrypt_resp = client
1198                .post(format!("{}/v1/transit/encrypt/{}", addr, msg.key_name))
1199                .header("X-Vault-Token", &msg.token)
1200                .json(&serde_json::json!({
1201                    "plaintext": "dGVzdA==" // Base64 encoded "test"
1202                }))
1203                .send()
1204                .await;
1205
1206            match encrypt_resp {
1207                Ok(resp) => {
1208                    if resp.status().is_success() {
1209                        // Successfully accessed a path that requires root permissions
1210                        if let Some(sender) = &actor.event_sender {
1211                            let _ = sender.send(VaultEvent::TokenVerified {
1212                                valid: true,
1213                                message: "Token has transit permissions".into(),
1214                            });
1215                        }
1216                        Ok(true)
1217                    } else {
1218                        let body = resp
1219                            .text()
1220                            .await
1221                            .unwrap_or_else(|_| "Unknown error".to_string());
1222                        if let Some(sender) = &actor.event_sender {
1223                            let _ = sender.send(VaultEvent::TokenVerified {
1224                                valid: false,
1225                                message: format!("Token verification failed: {}", body),
1226                            });
1227                        }
1228                        Err(ActorError::VaultApi(format!(
1229                            "Token permission verification failed: {}",
1230                            body
1231                        )))
1232                    }
1233                }
1234                Err(e) => {
1235                    if let Some(sender) = &actor.event_sender {
1236                        let _ = sender.send(VaultEvent::TokenVerified {
1237                            valid: false,
1238                            message: format!("Token verification failed: {}", e),
1239                        });
1240                    }
1241                    Err(ActorError::Network(format!(
1242                        "Token verification request failed: {}",
1243                        e
1244                    )))
1245                }
1246            }
1247        })
1248    }
1249}
1250
1251// Add new message type for checking dependencies immediately
1252#[derive(Message, Debug, Clone)]
1253#[rtype(result = "Result<(), ActorError>")]
1254pub struct CheckDependencies;
1255
1256/// Helper function to check the health status of a vault
1257async fn check_vault_health(
1258    client: &reqwest::Client,
1259    addr: &str,
1260) -> Result<VaultHealth, ActorError> {
1261    let status_url = format!("{}/v1/sys/health", addr);
1262
1263    let response = client
1264        .get(&status_url)
1265        .send()
1266        .await
1267        .map_err(|e| ActorError::Network(format!("Failed to connect to {}: {}", addr, e)))?;
1268
1269    if !response.status().is_success() {
1270        return if response.status() == StatusCode::INTERNAL_SERVER_ERROR {
1271            // Sealed vault returns 500 status, but we still want the response body
1272            let health_data: serde_json::Value = response.json().await.map_err(|e| {
1273                ActorError::VaultApi(format!("Could not parse vault health response: {}", e))
1274            })?;
1275
1276            // Extract fields from JSON
1277            let initialized = health_data
1278                .get("initialized")
1279                .and_then(|v| v.as_bool())
1280                .unwrap_or(false);
1281            let sealed = health_data
1282                .get("sealed")
1283                .and_then(|v| v.as_bool())
1284                .unwrap_or(true);
1285            let standby = health_data
1286                .get("standby")
1287                .and_then(|v| v.as_bool())
1288                .unwrap_or(false);
1289
1290            Ok(VaultHealth {
1291                addr: addr.to_string(),
1292                initialized,
1293                sealed,
1294                standby,
1295                last_check: std::time::SystemTime::now(),
1296                is_auto_unsealed: false, // Will be updated later if needed
1297                unsealer_addr: None,
1298            })
1299        } else {
1300            Err(ActorError::VaultApi(format!(
1301                "Vault health check failed with status code: {}",
1302                response.status()
1303            )))
1304        };
1305    }
1306
1307    // Parse response
1308    let health_data: serde_json::Value = response.json().await.map_err(|e| {
1309        ActorError::VaultApi(format!("Could not parse vault health response: {}", e))
1310    })?;
1311
1312    // Extract fields from JSON
1313    let initialized = health_data
1314        .get("initialized")
1315        .and_then(|v| v.as_bool())
1316        .unwrap_or(false);
1317    let sealed = health_data
1318        .get("sealed")
1319        .and_then(|v| v.as_bool())
1320        .unwrap_or(true);
1321    let standby = health_data
1322        .get("standby")
1323        .and_then(|v| v.as_bool())
1324        .unwrap_or(false);
1325
1326    Ok(VaultHealth {
1327        addr: addr.to_string(),
1328        initialized,
1329        sealed,
1330        standby,
1331        last_check: std::time::SystemTime::now(),
1332        is_auto_unsealed: false, // Will be updated later if needed
1333        unsealer_addr: None,
1334    })
1335}
1336
1337/// Function to check auto-unseal dependencies between a sub vault and its root vault
1338async fn check_auto_unseal_dependencies(
1339    _client: &reqwest::Client,
1340    sub_addr: &str,
1341    sub_health: &VaultHealth,
1342    root_addr: &str,
1343    root_health: &VaultHealth,
1344    event_tx: &broadcast::Sender<VaultEvent>,
1345) -> Result<(), ActorError> {
1346    // Log health status for debugging
1347    info!(
1348        "Checking auto-unseal dependency: sub_vault={} (sealed={}, init={}), root_vault={} (sealed={}, init={})",
1349        sub_addr, sub_health.sealed, sub_health.initialized,
1350        root_addr, root_health.sealed, root_health.initialized
1351    );
1352
1353    // Check for dependency issues
1354    if root_health.sealed || !root_health.initialized {
1355        // Root vault has issues that would prevent auto-unsealing
1356        let error_msg = if root_health.sealed {
1357            format!(
1358                "Root vault at {} is sealed, which prevents auto-unsealing of the sub vault at {}",
1359                root_addr, sub_addr
1360            )
1361        } else {
1362            format!("Root vault at {} is not initialized, which prevents auto-unsealing of the sub vault at {}",
1363                    root_addr, sub_addr)
1364        };
1365
1366        error!("Auto-unseal dependency issue detected: {}", error_msg);
1367
1368        // Emit event
1369        if let Err(e) = event_tx.send(VaultEvent::AutoUnsealDependencyError {
1370            sub_addr: sub_addr.to_string(),
1371            root_addr: root_addr.to_string(),
1372            error: error_msg,
1373        }) {
1374            error!("Failed to send AutoUnsealDependencyError event: {}", e);
1375        }
1376    }
1377
1378    Ok(())
1379}
1380
1381impl Handler<CheckDependencies> for VaultActor {
1382    type Result = ResponseFuture<Result<(), ActorError>>;
1383
1384    fn handle(&mut self, _msg: CheckDependencies, _ctx: &mut Self::Context) -> Self::Result {
1385        let unsealer_relationships = self.unsealer_relationships.clone();
1386        let known_vaults = self.known_vaults.clone();
1387        let event_tx = self.event_sender.clone().unwrap();
1388        let client = reqwest::Client::new();
1389
1390        Box::pin(async move {
1391            info!("Checking auto-unseal dependencies...");
1392
1393            // Log current state for debugging
1394            info!("Known vaults: {:?}", known_vaults);
1395            info!("Unsealer relationships: {:?}", unsealer_relationships);
1396
1397            // For each sub vault that has a root vault for auto-unsealing
1398            for (sub_addr, root_addr) in &unsealer_relationships {
1399                // Aggressively check root vault health first
1400                let root_health = match check_vault_health(&client, root_addr).await {
1401                    Ok(health) => {
1402                        info!(
1403                            "Root vault health at {}: sealed={}, initialized={}",
1404                            root_addr, health.sealed, health.initialized
1405                        );
1406                        health
1407                    }
1408                    Err(e) => {
1409                        // Root vault is unreachable - emit error event
1410                        error!("Root vault {} is unreachable: {}", root_addr, e);
1411                        let error_msg = format!("Root vault is unreachable: {}", e);
1412
1413                        if let Err(e) = event_tx.send(VaultEvent::AutoUnsealDependencyError {
1414                            sub_addr: sub_addr.clone(),
1415                            root_addr: root_addr.clone(),
1416                            error: error_msg,
1417                        }) {
1418                            error!("Failed to send event: {}", e);
1419                        }
1420
1421                        continue;
1422                    }
1423                };
1424
1425                // Check if root vault is in a state that prevents auto-unseal
1426                if root_health.sealed || !root_health.initialized {
1427                    // Root vault is sealed or not initialized - emit error event
1428                    let error_msg = if root_health.sealed {
1429                        format!("Root vault {} is sealed", root_addr)
1430                    } else {
1431                        format!("Root vault {} is not initialized", root_addr)
1432                    };
1433
1434                    error!("Auto-unseal dependency issue detected: {}", error_msg);
1435
1436                    if let Err(e) = event_tx.send(VaultEvent::AutoUnsealDependencyError {
1437                        sub_addr: sub_addr.clone(),
1438                        root_addr: root_addr.clone(),
1439                        error: error_msg,
1440                    }) {
1441                        error!("Failed to send event: {}", e);
1442                    }
1443
1444                    continue;
1445                }
1446
1447                // Now check sub vault health
1448                let sub_health = match check_vault_health(&client, sub_addr).await {
1449                    Ok(health) => {
1450                        info!(
1451                            "Sub vault health at {}: sealed={}, initialized={}",
1452                            sub_addr, health.sealed, health.initialized
1453                        );
1454                        health
1455                    }
1456                    Err(e) => {
1457                        // Sub vault is unreachable - log but don't emit event yet
1458                        warn!("Sub vault {} is unreachable: {}", sub_addr, e);
1459                        continue;
1460                    }
1461                };
1462
1463                // We've checked both vaults - now call the dependency check function
1464                if let Err(e) = check_auto_unseal_dependencies(
1465                    &client,
1466                    sub_addr,
1467                    &sub_health,
1468                    root_addr,
1469                    &root_health,
1470                    &event_tx,
1471                )
1472                .await
1473                {
1474                    error!("Failed to check auto-unseal dependencies: {}", e);
1475                }
1476            }
1477
1478            Ok(())
1479        })
1480    }
1481}
1482
1483// Add new message type for getting the actor's current vault address
1484#[derive(Message, Debug, Clone)]
1485#[rtype(result = "Result<String, ActorError>")]
1486pub struct GetCurrentAddress;
1487
1488impl Handler<GetCurrentAddress> for VaultActor {
1489    type Result = ResponseFuture<Result<String, ActorError>>;
1490
1491    fn handle(&mut self, _: GetCurrentAddress, _ctx: &mut Context<Self>) -> Self::Result {
1492        let addr = self.vault_addr.clone();
1493        async move { Ok(addr) }.boxed_local()
1494    }
1495}
1496
1497// Add new message type for setting the actor's current vault address
1498#[derive(Message, Debug, Clone)]
1499#[rtype(result = "Result<(), ActorError>")]
1500pub struct SetCurrentAddress(pub String);
1501
1502impl Handler<SetCurrentAddress> for VaultActor {
1503    type Result = ResponseFuture<Result<(), ActorError>>;
1504
1505    fn handle(&mut self, msg: SetCurrentAddress, _ctx: &mut Context<Self>) -> Self::Result {
1506        let new_addr = msg.0;
1507        info!("Setting current vault address to {}", new_addr);
1508        self.vault_addr = new_addr.clone();
1509
1510        // Try to load token for the new vault address from database
1511        if self.root_token.is_none() && self.db_manager.is_some() {
1512            if let Some(db) = &self.db_manager {
1513                match db.load_vault_credentials() {
1514                    Ok(credentials) => {
1515                        if !credentials.root_token.is_empty() {
1516                            info!(
1517                                "Loaded root token from database for vault {}",
1518                                self.vault_addr
1519                            );
1520                            self.root_token = Some(credentials.root_token);
1521                        }
1522                    }
1523                    Err(e) => {
1524                        warn!("Failed to load credentials from database: {}", e);
1525                    }
1526                }
1527            }
1528        }
1529
1530        Box::pin(async move { Ok(()) })
1531    }
1532}
1533
1534// Add new message type for adding an unsealer relationship
1535#[derive(Message, Debug, Clone)]
1536#[rtype(result = "Result<(), ActorError>")]
1537pub struct AddUnsealerRelationship {
1538    pub sub_addr: String,
1539    pub root_addr: String,
1540}
1541
1542impl Handler<AddUnsealerRelationship> for VaultActor {
1543    type Result = ResponseFuture<Result<(), ActorError>>;
1544
1545    fn handle(&mut self, msg: AddUnsealerRelationship, _ctx: &mut Context<Self>) -> Self::Result {
1546        // Update the relationship in the actor instance
1547        self.unsealer_relationships
1548            .insert(msg.sub_addr.clone(), msg.root_addr.clone());
1549
1550        // Log for debugging
1551        info!(
1552            "Added unsealer relationship: sub={}, root={}",
1553            msg.sub_addr, msg.root_addr
1554        );
1555
1556        // Save to database if available
1557        let db_manager = self.db_manager.clone();
1558        let sub_addr = msg.sub_addr.clone();
1559        let root_addr = msg.root_addr.clone();
1560
1561        // Clone values for async
1562        let mut actor = self.clone();
1563
1564        async move {
1565            // Save to the database if we have a database manager
1566            if let Some(db) = db_manager {
1567                if let Err(e) = db.save_unsealer_relationship(&sub_addr, &root_addr) {
1568                    warn!("Failed to save unsealer relationship to database: {}", e);
1569                }
1570            }
1571
1572            // Register both vaults
1573            actor.register_vault(sub_addr.clone()).await;
1574            actor.register_vault(root_addr.clone()).await;
1575
1576            // Check if the root vault has any issues
1577            if let Ok(root_status) = actor.check_status(&root_addr).await {
1578                if root_status.sealed || !root_status.initialized {
1579                    let error_msg = if root_status.sealed {
1580                        format!(
1581                            "Root vault is sealed - sub vault {} will not be able to auto-unseal",
1582                            sub_addr
1583                        )
1584                    } else {
1585                        format!(
1586                            "Root vault is not initialized - sub vault {} will not be able to auto-unseal",
1587                            sub_addr
1588                        )
1589                    };
1590                    warn!("{}", error_msg);
1591
1592                    // Emit event for this warning
1593                    if let Some(sender) = &actor.event_sender {
1594                        let _ = sender.send(VaultEvent::Error(error_msg));
1595                    }
1596                }
1597            }
1598
1599            Ok(())
1600        }
1601        .boxed_local()
1602    }
1603}
1604
1605// Add new message type for explicitly registering a vault
1606#[derive(Message, Debug, Clone)]
1607#[rtype(result = "Result<(), ActorError>")]
1608pub struct RegisterVault(pub String);
1609
1610impl Handler<RegisterVault> for VaultActor {
1611    type Result = ResponseFuture<Result<(), ActorError>>;
1612
1613    fn handle(&mut self, msg: RegisterVault, _ctx: &mut Context<Self>) -> Self::Result {
1614        // Clone for async to avoid borrowing issues
1615        let addr = msg.0;
1616        let mut actor = self.clone();
1617
1618        async move {
1619            // Register the vault
1620            actor.register_vault(addr.clone()).await;
1621            info!("Registered vault: {}", addr);
1622            Ok(())
1623        }
1624        .boxed_local()
1625    }
1626}
1627
1628/// Message to seal a vault intentionally
1629#[derive(Message)]
1630#[rtype(result = "Result<(), ActorError>")]
1631pub struct SealVault {
1632    pub token: String,
1633}
1634
1635impl Handler<SealVault> for VaultActor {
1636    type Result = ResponseFuture<Result<(), ActorError>>;
1637
1638    fn handle(&mut self, msg: SealVault, _ctx: &mut Self::Context) -> Self::Result {
1639        let address = self.vault_addr.clone();
1640        let token = msg.token.clone();
1641        let event_sender = self.event_sender.clone();
1642
1643        Box::pin(async move {
1644            info!("Sealing vault at {}", address);
1645
1646            match crate::vault::seal_vault(&address, &token).await {
1647                Ok(_) => {
1648                    info!("Successfully sealed vault at {}", address);
1649
1650                    // Send an event if applicable
1651                    if let Some(sender) = &event_sender {
1652                        let _ = sender.send(VaultEvent::Error(format!(
1653                            "Vault at {} was intentionally sealed",
1654                            address
1655                        )));
1656                    }
1657
1658                    Ok(())
1659                }
1660                Err(err) => {
1661                    error!("Failed to seal vault: {}", err);
1662
1663                    if let Some(sender) = &event_sender {
1664                        let _ = sender.send(VaultEvent::Error(format!(
1665                            "Failed to seal vault at {}: {}",
1666                            address, err
1667                        )));
1668                    }
1669
1670                    Err(ActorError::VaultApi(format!(
1671                        "Failed to seal vault: {}",
1672                        err
1673                    )))
1674                }
1675            }
1676        })
1677    }
1678}
1679
1680// Add new message type for setting the root token directly
1681#[derive(Message, Debug, Clone)]
1682#[rtype(result = "Result<(), ActorError>")]
1683pub struct SetRootToken(pub String);
1684
1685impl Handler<SetRootToken> for VaultActor {
1686    type Result = Result<(), ActorError>;
1687
1688    fn handle(&mut self, msg: SetRootToken, _ctx: &mut Context<Self>) -> Self::Result {
1689        debug!("Setting root token in VaultActor");
1690        self.root_token = Some(msg.0);
1691        Ok(())
1692    }
1693}
1694
1695// New message types for syncing tokens with the database
1696pub struct SyncToken {
1697    pub addr: String,
1698    pub token: String,
1699}
1700
1701impl Message for SyncToken {
1702    type Result = Result<(), ActorError>;
1703}
1704
1705impl Handler<SyncToken> for VaultActor {
1706    type Result = ResponseFuture<Result<(), ActorError>>;
1707
1708    fn handle(&mut self, msg: SyncToken, _ctx: &mut Self::Context) -> Self::Result {
1709        // Update this actor's token if the address matches
1710        if self.vault_addr == msg.addr {
1711            self.root_token = Some(msg.token.clone());
1712        }
1713
1714        // Save to database if available
1715        let token = msg.token.clone();
1716        let db_manager = self.db_manager.clone();
1717
1718        Box::pin(async move {
1719            if let Some(db) = db_manager {
1720                // Try to load existing credentials first
1721                let mut credentials = match db.load_vault_credentials() {
1722                    Ok(creds) => {
1723                        info!("Loaded existing credentials from database for token update");
1724                        creds
1725                    }
1726                    Err(e) => {
1727                        warn!("Failed to load credentials from database: {}. Creating new credentials.", e);
1728                        VaultCredentials::default()
1729                    }
1730                };
1731
1732                // Update root token
1733                credentials.root_token = token;
1734                info!(
1735                    "Updated root token in credentials (length: {})",
1736                    credentials.root_token.len()
1737                );
1738
1739                // Save back to database
1740                if let Err(e) = db.save_vault_credentials(&credentials) {
1741                    warn!("Failed to save root token to database: {}", e);
1742                    return Err(ActorError::Operation(format!(
1743                        "Failed to save root token: {}",
1744                        e
1745                    )));
1746                }
1747
1748                info!("Successfully saved root token to database");
1749            }
1750            Ok(())
1751        })
1752    }
1753}
1754
1755pub struct SyncTransitToken {
1756    pub addr: String,
1757    pub token: String,
1758}
1759
1760impl Message for SyncTransitToken {
1761    type Result = Result<(), ActorError>;
1762}
1763
1764impl Handler<SyncTransitToken> for VaultActor {
1765    type Result = ResponseFuture<Result<(), ActorError>>;
1766
1767    fn handle(&mut self, msg: SyncTransitToken, _ctx: &mut Self::Context) -> Self::Result {
1768        // Note: We don't update the actor's state with transit token as it's not stored there
1769        // Just save to database
1770        let token = msg.token.clone();
1771        let db_manager = self.db_manager.clone();
1772
1773        Box::pin(async move {
1774            if let Some(db) = db_manager {
1775                // Try to load existing credentials first
1776                let mut credentials = match db.load_vault_credentials() {
1777                    Ok(creds) => {
1778                        info!("Loaded existing credentials from database for transit token update");
1779                        creds
1780                    }
1781                    Err(e) => {
1782                        warn!("Failed to load credentials from database: {}. Creating new credentials.", e);
1783                        VaultCredentials::default()
1784                    }
1785                };
1786
1787                // Update transit token
1788                credentials.transit_token = token;
1789                info!(
1790                    "Updated transit token in credentials (length: {})",
1791                    credentials.transit_token.len()
1792                );
1793
1794                // Save back to database
1795                if let Err(e) = db.save_vault_credentials(&credentials) {
1796                    warn!("Failed to save transit token to database: {}", e);
1797                    return Err(ActorError::Operation(format!(
1798                        "Failed to save transit token: {}",
1799                        e
1800                    )));
1801                }
1802
1803                info!("Successfully saved transit token to database");
1804            }
1805            Ok(())
1806        })
1807    }
1808}
1809
1810// Add SyncSubToken message
1811pub struct SyncSubToken {
1812    pub addr: String,
1813    pub token: String,
1814}
1815
1816impl Message for SyncSubToken {
1817    type Result = Result<(), ActorError>;
1818}
1819
1820impl Handler<SyncSubToken> for VaultActor {
1821    type Result = ResponseFuture<Result<(), ActorError>>;
1822
1823    fn handle(&mut self, msg: SyncSubToken, _ctx: &mut Self::Context) -> Self::Result {
1824        // Save sub token to database
1825        let token = msg.token.clone();
1826        let db_manager = self.db_manager.clone();
1827
1828        Box::pin(async move {
1829            if let Some(db) = db_manager {
1830                // Try to load existing credentials first
1831                let mut credentials = match db.load_vault_credentials() {
1832                    Ok(creds) => {
1833                        info!("Loaded existing credentials from database for sub token update");
1834                        creds
1835                    }
1836                    Err(e) => {
1837                        warn!("Failed to load credentials from database: {}. Creating new credentials.", e);
1838                        VaultCredentials::default()
1839                    }
1840                };
1841
1842                // Update sub token
1843                credentials.sub_token = token;
1844                info!(
1845                    "Updated sub token in credentials (length: {})",
1846                    credentials.sub_token.len()
1847                );
1848
1849                // Save back to database
1850                if let Err(e) = db.save_vault_credentials(&credentials) {
1851                    warn!("Failed to save sub token to database: {}", e);
1852                    return Err(ActorError::Operation(format!(
1853                        "Failed to save sub token: {}",
1854                        e
1855                    )));
1856                }
1857
1858                info!("Successfully saved sub token to database");
1859            }
1860            Ok(())
1861        })
1862    }
1863}
1864
1865// -----------------------------------------------------------------------------
1866// Start the actor with a broadcast channel
1867// -----------------------------------------------------------------------------
1868
1869pub fn start_vault_actor_with_channel(
1870    vault_addr: &str,
1871) -> (Addr<VaultActor>, broadcast::Receiver<VaultEvent>) {
1872    let (tx, rx) = broadcast::channel(16);
1873    let actor = VaultActor::new(vault_addr, Some(tx));
1874
1875    // Clone the actor before starting it
1876    let monitoring_actor = actor.clone();
1877    let addr = actor.start();
1878
1879    // Start the monitoring in the background
1880    tokio::spawn(async move {
1881        let mut monitoring_actor = monitoring_actor;
1882        monitoring_actor.start_monitoring().await;
1883    });
1884
1885    (addr, rx)
1886}
1887
1888#[async_trait]
1889impl VaultInterface for VaultActor {
1890    async fn check_status(&self, addr: &str) -> Result<VaultStatus, VaultError> {
1891        match crate::vault::common::check_vault_status(addr).await {
1892            Ok(status) => {
1893                if let Some(sender) = &self.event_sender {
1894                    let _ = sender.send(VaultEvent::StatusChecked {
1895                        initialized: status.initialized,
1896                        sealed: status.sealed,
1897                        standby: status.standby,
1898                    });
1899                }
1900                Ok(status)
1901            }
1902            Err(err) => Err(VaultError::Api(format!("Status check error: {}", err))),
1903        }
1904    }
1905
1906    async fn unseal(&self, addr: &str, keys: Vec<String>) -> Result<UnsealResult, VaultError> {
1907        match crate::vault::init::unseal_root_vault(addr, keys).await {
1908            Ok(unseal_resp) => {
1909                if let Some(sender) = &self.event_sender {
1910                    let _ = sender.send(VaultEvent::Unsealed {
1911                        progress: unseal_resp.progress,
1912                        threshold: unseal_resp.threshold,
1913                        sealed: unseal_resp.sealed,
1914                    });
1915                }
1916                Ok(unseal_resp)
1917            }
1918            Err(err) => Err(VaultError::Api(format!("Unseal error: {}", err))),
1919        }
1920    }
1921
1922    async fn setup_root(
1923        &self,
1924        addr: &str,
1925        secret_shares: u8,
1926        secret_threshold: u8,
1927        key_name: &str,
1928    ) -> Result<String, VaultError> {
1929        let config = RootSetupConfig {
1930            root_addr: addr.to_string(),
1931            secret_shares,
1932            secret_threshold,
1933            key_name: key_name.to_string(),
1934            mode: "local".to_string(),
1935            output_file: None,
1936        };
1937
1938        match setup_root_vault(config).await {
1939            Ok(result) => {
1940                if let Some(sender) = &self.event_sender {
1941                    let _ = sender.send(VaultEvent::Initialized {
1942                        root_token: result.root_init.root_token.clone(),
1943                        keys: result.root_init.keys.clone(),
1944                    });
1945                }
1946                Ok(result.unwrapped_token)
1947            }
1948            Err(e) => Err(VaultError::Api(format!("Root setup error: {}", e))),
1949        }
1950    }
1951
1952    async fn setup_sub(
1953        &self,
1954        root_addr: &str,
1955        root_token: &str,
1956        sub_addr: &str,
1957        domain: &str,
1958        ttl: &str,
1959    ) -> Result<String, VaultError> {
1960        let config = SubSetupConfig {
1961            sub_addr: sub_addr.to_string(),
1962            domain: domain.to_string(),
1963            ttl: ttl.to_string(),
1964            root_addr: root_addr.to_string(),
1965            root_token: root_token.to_string(),
1966        };
1967
1968        match setup_sub_vault(config).await {
1969            Ok(SubSetupResult {
1970                sub_init,
1971                pki_roles,
1972            }) => {
1973                if let Some(sender) = &self.event_sender {
1974                    let _ = sender.send(VaultEvent::SetupComplete {
1975                        root_token: sub_init.root_token.clone(),
1976                        root_role: pki_roles.0.clone(),
1977                        sub_token: sub_init.root_token,
1978                        int_role: pki_roles.1.clone(),
1979                    });
1980                }
1981                Ok(pki_roles.1)
1982            }
1983            Err(e) => Err(VaultError::Api(format!("Sub setup error: {}", e))),
1984        }
1985    }
1986
1987    async fn get_unwrapped_transit_token(
1988        &self,
1989        root_addr: &str,
1990        root_token: &str,
1991        key_name: &str,
1992    ) -> Result<String, VaultError> {
1993        debug!(
1994            "Getting unwrapped transit token from root vault at {}",
1995            root_addr
1996        );
1997
1998        // First, ensure transit auto-unseal is set up
1999        if let Err(e) =
2000            crate::vault::autounseal::setup_transit_autounseal(root_addr, root_token, key_name)
2001                .await
2002        {
2003            return Err(VaultError::Api(format!(
2004                "Failed to setup transit auto-unseal: {}",
2005                e
2006            )));
2007        }
2008
2009        // Generate a wrapped transit token
2010        let wrap_ttl = "300s";
2011        let wrapped_token = match crate::vault::transit::generate_wrapped_transit_token(
2012            root_addr,
2013            root_token,
2014            "autounseal", // policy name used in setup_transit_autounseal
2015            wrap_ttl,
2016        )
2017        .await
2018        {
2019            Ok(token) => token,
2020            Err(e) => {
2021                return Err(VaultError::Api(format!(
2022                    "Failed to generate wrapped token: {}",
2023                    e
2024                )))
2025            }
2026        };
2027
2028        // Unwrap the token
2029        let unwrapped_token =
2030            match crate::vault::autounseal::unwrap_token(root_addr, &wrapped_token).await {
2031                Ok(token) => token,
2032                Err(e) => return Err(VaultError::Api(format!("Failed to unwrap token: {}", e))),
2033            };
2034
2035        debug!("Successfully obtained unwrapped transit token");
2036
2037        // Emit event if sender is available
2038        if let Some(sender) = &self.event_sender {
2039            let _ = sender.send(VaultEvent::TransitTokenUnwrapped {
2040                root_addr: root_addr.to_string(),
2041                unwrapped_token: unwrapped_token.clone(),
2042            });
2043        }
2044
2045        Ok(unwrapped_token)
2046    }
2047}