Skip to main content

lit/commands/
config.rs

1use crate::network::{AirgapConfig, NetworkConfig};
2use crate::response::{ConfigEntry, ConfigResponse};
3
4pub fn execute(
5    command: Option<crate::ConfigCommands>,
6) -> Result<ConfigResponse, crate::errors::LitError> {
7    match command {
8        Some(crate::ConfigCommands::Show) | None => show_config(),
9        Some(crate::ConfigCommands::Get { key }) => get_config(&key),
10        Some(crate::ConfigCommands::Set { key, value }) => set_config(&key, &value),
11    }
12}
13
14fn show_config() -> Result<ConfigResponse, crate::errors::LitError> {
15    let network_config = NetworkConfig::load()?;
16    let airgap_config = AirgapConfig::load()?;
17
18    let mut entries = Vec::new();
19
20    entries.push(ConfigEntry {
21        key: "airgap.enabled".to_string(),
22        value: airgap_config.enabled.to_string(),
23    });
24    entries.push(ConfigEntry {
25        key: "airgap.strict_mode".to_string(),
26        value: airgap_config.strict_mode.to_string(),
27    });
28    entries.push(ConfigEntry {
29        key: "airgap.allowed_transports".to_string(),
30        value: format!("{:?}", airgap_config.allowed_transports),
31    });
32    if !airgap_config.allowed_media.is_empty() {
33        entries.push(ConfigEntry {
34            key: "airgap.allowed_media".to_string(),
35            value: airgap_config.allowed_media.join(", "),
36        });
37    }
38    if !airgap_config.allowed_shares.is_empty() {
39        entries.push(ConfigEntry {
40            key: "airgap.allowed_shares".to_string(),
41            value: airgap_config.allowed_shares.join(", "),
42        });
43    }
44    entries.push(ConfigEntry {
45        key: "network.allowed_networks".to_string(),
46        value: network_config.allowed_networks.join(", "),
47    });
48    entries.push(ConfigEntry {
49        key: "network.allowed_hosts".to_string(),
50        value: if network_config.allowed_hosts.is_empty() {
51            "(none)".to_string()
52        } else {
53            network_config.allowed_hosts.join(", ")
54        },
55    });
56    entries.push(ConfigEntry {
57        key: "security.network_audit_log".to_string(),
58        value: network_config.audit_log.to_string(),
59    });
60    if let Some(path) = &network_config.audit_log_path {
61        entries.push(ConfigEntry {
62            key: "security.network_audit_log_path".to_string(),
63            value: path.clone(),
64        });
65    }
66    entries.push(ConfigEntry {
67        key: "security.airgap_audit_log".to_string(),
68        value: airgap_config.audit_log.to_string(),
69    });
70    if let Some(path) = &airgap_config.audit_log_path {
71        entries.push(ConfigEntry {
72            key: "security.airgap_audit_log_path".to_string(),
73            value: path.clone(),
74        });
75    }
76
77    Ok(ConfigResponse::Show { entries })
78}
79
80fn get_config(key: &str) -> Result<ConfigResponse, crate::errors::LitError> {
81    let network_config = NetworkConfig::load()?;
82    let airgap_config = AirgapConfig::load()?;
83
84    let value = match key {
85        "airgap.enabled" => airgap_config.enabled.to_string(),
86        "airgap.strict_mode" => airgap_config.strict_mode.to_string(),
87        "network.allowed_networks" => network_config.allowed_networks.join(", "),
88        "network.allowed_hosts" => network_config.allowed_hosts.join(", "),
89        "security.audit_log" => network_config.audit_log.to_string(),
90        "security.audit_log_path" => network_config.audit_log_path.unwrap_or_default(),
91        _ => return Err(format!("Unknown configuration key: {}", key).into()),
92    };
93
94    Ok(ConfigResponse::Get {
95        key: key.to_string(),
96        value,
97    })
98}
99
100fn set_config(key: &str, value: &str) -> Result<ConfigResponse, crate::errors::LitError> {
101    match key {
102        "airgap.enabled" => {
103            let mut config = AirgapConfig::load()?;
104            config.enabled = value
105                .parse::<bool>()
106                .map_err(|_| "Invalid boolean value (use 'true' or 'false')".to_string())?;
107            config.save()?;
108            Ok(ConfigResponse::Set {
109                key: key.to_string(),
110                value: value.to_string(),
111            })
112        }
113        "airgap.strict_mode" => {
114            let mut config = AirgapConfig::load()?;
115            config.strict_mode = value
116                .parse::<bool>()
117                .map_err(|_| "Invalid boolean value (use 'true' or 'false')".to_string())?;
118            config.save()?;
119            Ok(ConfigResponse::Set {
120                key: key.to_string(),
121                value: value.to_string(),
122            })
123        }
124        _ => Err(format!(
125            "Setting '{}' is not supported via command line.\n\
126                 Supported keys: airgap.enabled, airgap.strict_mode\n\
127                 For other settings, edit ~/.lit/airgap.toml or ~/.litconfig directly.",
128            key
129        )
130        .into()),
131    }
132}