1
use clap::Args;
2
use console::style;
3
use mk_lib::secrets::{
4
  load_secret_value,
5
  verify_vault,
6
};
7
use prettytable::format::consts;
8
use prettytable::{
9
  row,
10
  Table,
11
};
12
use std::io::Write as _;
13

            
14
use crate::secrets::context::Context;
15

            
16
#[derive(Debug, Args)]
17
pub struct ShowSecret {
18
  #[arg(help = "The secret identifier")]
19
  path: String,
20

            
21
  #[arg(short, long, help = "The path to the secret store")]
22
  vault_location: Option<String>,
23

            
24
  #[arg(long, help = "The keys location")]
25
  keys_location: Option<String>,
26

            
27
  #[arg(short, long, help = "The key name", conflicts_with = "gpg_key_id")]
28
  key_name: Option<String>,
29

            
30
  #[arg(
31
    long,
32
    conflicts_with = "key_name",
33
    help = "GPG key ID or fingerprint for hardware/passphrase-protected keys. Cannot be combined with --key-name."
34
  )]
35
  gpg_key_id: Option<String>,
36

            
37
  #[arg(short, long, help = "Print raw secret value without table formatting")]
38
  plain: bool,
39
}
40

            
41
impl ShowSecret {
42
  pub fn execute(&self, context: &Context) -> anyhow::Result<()> {
43
    let path: &str = &self.path.clone();
44
    let mut cli_overrides = context.settings().clone();
45
    if let Some(vault_location) = &self.vault_location {
46
      cli_overrides.vault_location = Some(vault_location.clone());
47
    }
48
    if let Some(keys_location) = &self.keys_location {
49
      cli_overrides.keys_location = Some(keys_location.clone());
50
    }
51
    if let Some(key_name) = &self.key_name {
52
      cli_overrides.key_name = Some(key_name.clone());
53
    }
54
    if let Some(gpg_key_id) = &self.gpg_key_id {
55
      cli_overrides.gpg_key_id = Some(gpg_key_id.clone());
56
    }
57
    let secret_config = context.resolve_with_settings(&cli_overrides);
58

            
59
    assert!(!path.is_empty(), "Path or prefix must be provided");
60

            
61
    verify_vault(&secret_config.vault_location)?;
62

            
63
    let value = load_secret_value(path, &secret_config)?;
64

            
65
    if self.plain {
66
      let mut stdout = std::io::stdout().lock();
67
      write!(stdout, "{}", value)?;
68
      stdout.flush()?;
69
      return Ok(());
70
    }
71

            
72
    let mut table = Table::new();
73
    table.set_format(*consts::FORMAT_CLEAN);
74
    table.set_titles(row![Fbb->"Name", Fbb->"Value"]);
75
    table.add_row(row![b->&path, Fg->&value]);
76

            
77
    let msg = style("Available secret:").bold().cyan();
78
    println!();
79
    println!("{msg}");
80
    println!();
81
    table.printstd();
82

            
83
    Ok(())
84
  }
85
}