use crate::crypto::agent;
use crate::crypto::encryption::{prompt_for_passphrase, EncryptionConfig};
use crate::errors::LitError;
use crate::response::AgentResponse;
use std::time::Duration;
fn repo_key() -> Result<String, LitError> {
let root = crate::core::find_repo_root()
.map_err(|e| LitError::Repository(format!("Not inside a repository: {e}")))?;
Ok(root.to_string_lossy().to_string())
}
pub fn start(timeout_secs: Option<u64>) -> Result<AgentResponse, LitError> {
let timeout = timeout_secs.unwrap_or(agent::DEFAULT_IDLE_TIMEOUT_SECS);
agent::serve(Duration::from_secs(timeout)).map_err(LitError::Encryption)?;
Ok(AgentResponse {
action: "stop".to_string(),
entries: Some(0),
idle_timeout_secs: Some(timeout),
message: "Agent stopped".to_string(),
})
}
pub fn unlock(timeout_secs: Option<u64>) -> Result<AgentResponse, LitError> {
let key = repo_key()?;
let root = crate::core::find_repo_root()
.map_err(|e| LitError::Repository(format!("Not inside a repository: {e}")))?;
let config = EncryptionConfig::load(&root).map_err(LitError::Config)?;
let passphrase = prompt_for_passphrase(&key, &config, "Passphrase: ")
.map_err(|e| LitError::Encryption(format!("Could not read passphrase: {e}")))?;
agent::put(&key, &passphrase).map_err(LitError::Encryption)?;
let (entries, idle) = agent::status().map_err(LitError::Encryption)?;
Ok(AgentResponse {
action: "unlock".to_string(),
entries: Some(entries),
idle_timeout_secs: Some(timeout_secs.unwrap_or(idle)),
message: format!("Passphrase held for {key}"),
})
}
pub fn lock(all: bool) -> Result<AgentResponse, LitError> {
let target = if all { None } else { Some(repo_key()?) };
agent::drop_entry(target.as_deref()).map_err(LitError::Encryption)?;
let (entries, idle) = agent::status().map_err(LitError::Encryption)?;
Ok(AgentResponse {
action: "lock".to_string(),
entries: Some(entries),
idle_timeout_secs: Some(idle),
message: if all {
"Forgot every held passphrase".to_string()
} else {
"Forgot this repository's passphrase".to_string()
},
})
}
pub fn status() -> Result<AgentResponse, LitError> {
match agent::status() {
Ok((entries, idle_timeout_secs)) => Ok(AgentResponse {
action: "status".to_string(),
entries: Some(entries),
idle_timeout_secs: Some(idle_timeout_secs),
message: format!(
"Agent running, holding {entries} passphrase(s), idle timeout {idle_timeout_secs}s"
),
}),
Err(_) => Ok(AgentResponse {
action: "status".to_string(),
entries: None,
idle_timeout_secs: None,
message: "No agent is running".to_string(),
}),
}
}
pub fn stop() -> Result<AgentResponse, LitError> {
agent::shutdown().map_err(LitError::Encryption)?;
Ok(AgentResponse {
action: "stop".to_string(),
entries: Some(0),
idle_timeout_secs: None,
message: "Agent stopped".to_string(),
})
}