use anyhow::Result;
use colored::Colorize;
use tsafe_cli::cli::{ConfigAction, ExecCustomInheritSetting, ExecModeSetting, ToggleSetting};
use tsafe_core::profile;
pub(crate) fn cmd_config(action: ConfigAction) -> Result<()> {
match action {
ConfigAction::Show => {
println!("Config file: {}", profile::config_path().display());
println!(" default_profile: {}", profile::get_default_profile());
println!(
" quick_unlock.auto_retrieve: {}",
if profile::get_auto_quick_unlock() {
"on"
} else {
"off"
}
);
println!(
" quick_unlock.retry_cooldown_secs: {}",
profile::get_quick_unlock_retry_cooldown_secs()
);
println!(" exec.mode: {}", profile::get_exec_mode().as_str());
println!(
" exec.custom_inherit: {}",
profile::get_exec_custom_inherit_mode().as_str()
);
println!(
" exec.auto_redact_output: {}",
if profile::get_exec_auto_redact_output() {
"on"
} else {
"off"
}
);
println!(
" exec.custom_deny_dangerous_env: {}",
if profile::get_exec_custom_deny_dangerous_env() {
"on"
} else {
"off"
}
);
let extra_sensitive = profile::get_exec_extra_sensitive_parent_vars();
if extra_sensitive.is_empty() {
println!(" exec.extra_sensitive_parent_vars: (none)");
println!(" Add one: tsafe config add-exec-extra-strip OPENAI_API_KEY");
} else {
println!(
" exec.extra_sensitive_parent_vars: {}",
extra_sensitive.join(", ")
);
println!(" Remove one: tsafe config remove-exec-extra-strip OPENAI_API_KEY");
}
if let Some(t) = profile::get_backup_new_profile_passwords_to() {
println!(" backup_new_profile_passwords_to: {t}");
println!(" When you create another vault, its master password is stored under profile-passwords/<profile> in that vault.");
println!(" Change with: tsafe config set-backup-vault main | default | off");
} else {
println!(" backup_new_profile_passwords_to: (not set — disabled)");
println!(" Enable: tsafe config set-backup-vault main");
}
Ok(())
}
ConfigAction::SetAutoQuickUnlock { mode } => {
let enabled = matches!(mode, ToggleSetting::On);
profile::set_auto_quick_unlock(enabled).map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} Automatic quick unlock is now {}.",
"✓".green(),
if enabled { "on" } else { "off" }
);
if enabled {
println!(
" Normal vault opens may use the OS credential store unless an agent or env password is already available."
);
} else {
println!(
" Normal vault opens now skip keychain / biometric prompts; use agent unlock, TSAFE_PASSWORD, or type the password instead."
);
}
Ok(())
}
ConfigAction::SetQuickUnlockRetryCooldown { seconds } => {
profile::set_quick_unlock_retry_cooldown_secs(seconds)
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} Automatic quick-unlock retry cooldown is now {} second(s).",
"✓".green(),
seconds
);
if seconds == 0 {
println!(" Automatic quick-unlock failures will not create a retry delay.");
} else {
println!(
" After a denied or failed automatic keychain read, tsafe will wait before retrying automatically."
);
}
Ok(())
}
ConfigAction::SetExecMode { mode } => {
let mode = match mode {
ExecModeSetting::Standard => profile::ExecMode::Standard,
ExecModeSetting::Hardened => profile::ExecMode::Hardened,
ExecModeSetting::Custom => profile::ExecMode::Custom,
};
profile::set_exec_mode(mode).map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} Default exec mode is now `{}`.",
"✓".green(),
mode.as_str()
);
if matches!(mode, profile::ExecMode::Custom) {
println!(
" Custom uses: exec.custom_inherit={}, exec.auto_redact_output={}, exec.custom_deny_dangerous_env={}",
profile::get_exec_custom_inherit_mode().as_str(),
if profile::get_exec_auto_redact_output() { "on" } else { "off" },
if profile::get_exec_custom_deny_dangerous_env() { "on" } else { "off" }
);
}
Ok(())
}
ConfigAction::SetBackupVault { target } => {
let t = target.trim();
let lower = t.to_ascii_lowercase();
if lower == "off" || lower == "none" || lower == "disable" {
profile::set_backup_new_profile_passwords_to(None)
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} Stopped copying new vault passwords into another profile.",
"✓".green()
);
return Ok(());
}
profile::validate_profile_name(t).map_err(|e| anyhow::anyhow!("{e}"))?;
profile::set_backup_new_profile_passwords_to(Some(t))
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} New vault master passwords will be copied into '{}' at profile-passwords/<new-profile>.",
"✓".green(),
t
);
println!(" Create that vault first if needed: tsafe --profile {t} init");
println!(" Protect '{t}' strongly — anyone who opens it can read those backup keys.");
Ok(())
}
ConfigAction::SetExecRedactOutput { mode } => {
let enabled = matches!(mode, ToggleSetting::On);
profile::set_exec_auto_redact_output(enabled).map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} `tsafe exec` custom-mode child output redaction default is now {}.",
"✓".green(),
if enabled { "on" } else { "off" }
);
if enabled {
println!(" Override per run with: tsafe exec --no-redact-output -- <cmd>");
} else {
println!(" Override per run with: tsafe exec --redact-output -- <cmd>");
}
Ok(())
}
ConfigAction::SetExecCustomInherit { mode } => {
let mode = match mode {
ExecCustomInheritSetting::Full => profile::ExecCustomInheritMode::Full,
ExecCustomInheritSetting::Minimal => profile::ExecCustomInheritMode::Minimal,
ExecCustomInheritSetting::Clean => profile::ExecCustomInheritMode::Clean,
};
profile::set_exec_custom_inherit_mode(mode).map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} `tsafe exec` custom-mode inherit strategy is now `{}`.",
"✓".green(),
mode.as_str()
);
Ok(())
}
ConfigAction::SetExecCustomDenyDangerousEnv { mode } => {
let enabled = matches!(mode, ToggleSetting::On);
profile::set_exec_custom_deny_dangerous_env(enabled)
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} `tsafe exec` custom-mode dangerous env handling is now `{}`.",
"✓".green(),
if enabled { "deny" } else { "warn" }
);
Ok(())
}
ConfigAction::AddExecExtraStrip { name } => {
profile::add_exec_extra_sensitive_parent_var(&name)
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!(
"{} `tsafe exec` will now strip parent env var `{}` before spawn.",
"✓".green(),
name.trim()
);
Ok(())
}
ConfigAction::RemoveExecExtraStrip { name } => {
let removed = profile::remove_exec_extra_sensitive_parent_var(&name)
.map_err(|e| anyhow::anyhow!("{e}"))?;
if removed {
println!(
"{} Removed `{}` from the extra exec strip list.",
"✓".green(),
name.trim()
);
} else {
println!(
"{} `{}` was not present in the extra exec strip list.",
"i".blue(),
name.trim()
);
}
Ok(())
}
}
}