1
use std::path::Path;
2

            
3
use clap::{
4
  Args,
5
  Subcommand,
6
};
7

            
8
pub use export_secrets::ExportSecret;
9
pub use init_vault::InitVault;
10
pub use list_secrets::ListSecrets;
11
pub use purge_secrets::PurgeSecret;
12
pub use show_secrets::ShowSecret;
13
pub use store_secret::StoreSecret;
14

            
15
use super::context::Context;
16

            
17
mod export_secrets;
18
mod init_vault;
19
mod list_secrets;
20
mod purge_secrets;
21
mod show_secrets;
22
mod store_secret;
23

            
24
#[derive(Debug, Args)]
25
pub struct Vault {
26
  #[command(subcommand)]
27
  command: Option<VaultCommand>,
28

            
29
  #[arg(short, long, help = "The path to the secret vault")]
30
  vault_location: Option<String>,
31
}
32

            
33
#[derive(Debug, Subcommand)]
34
enum VaultCommand {
35
  #[command(visible_aliases = ["init"], about = "Initialize a new secret vault")]
36
  InitVault(InitVault),
37

            
38
  #[command(visible_aliases = ["list", "ls"], about = "List available secrets")]
39
  ListSecrets(ListSecrets),
40

            
41
  #[command(visible_aliases = ["store", "set"], arg_required_else_help = true, about = "Store a secret")]
42
  StoreSecret(StoreSecret),
43

            
44
  #[command(visible_aliases = ["show", "get", "s"], arg_required_else_help = true, about = "Retrieve a secret")]
45
  ShowSecret(ShowSecret),
46

            
47
  #[command(visible_aliases = ["purge", "rm"], arg_required_else_help = true, about = "Purge and delete a secret")]
48
  PurgeSecret(PurgeSecret),
49

            
50
  #[command(
51
    visible_aliases = ["export", "e"],
52
    arg_required_else_help = true,
53
    about = "Export a secret to a file"
54
  )]
55
  ExportSecret(ExportSecret),
56
}
57

            
58
impl Vault {
59
  pub fn execute(&self, context: &mut Context) -> anyhow::Result<()> {
60
    if let Some(vault_location) = &self.vault_location {
61
      context.set_vault_location(vault_location);
62
    }
63

            
64
    match &self.command {
65
      Some(command) => command.run(context),
66
      None => Err(anyhow::anyhow!(
67
        "No vault subcommand given. Run 'mk secrets vault --help' to see available subcommands."
68
      )),
69
    }
70
  }
71
}
72

            
73
impl VaultCommand {
74
  pub fn run(&self, context: &Context) -> anyhow::Result<()> {
75
    match self {
76
      VaultCommand::InitVault(init_vault) => init_vault.execute(context),
77
      VaultCommand::ListSecrets(list_secrets) => list_secrets.execute(context),
78
      VaultCommand::StoreSecret(store_secret) => store_secret.execute(context),
79
      VaultCommand::ShowSecret(show_secret) => show_secret.execute(context),
80
      VaultCommand::PurgeSecret(purge_secret) => purge_secret.execute(context),
81
      VaultCommand::ExportSecret(export_secret) => export_secret.execute(context),
82
    }
83
  }
84
}
85

            
86
fn verify_key(keys_location: &str, key_name: &str) -> anyhow::Result<()> {
87
  let keys_path = Path::new(keys_location);
88
  if !keys_path.exists() || !keys_path.is_dir() {
89
    anyhow::bail!(
90
      "Keys directory not found at '{}'. Generate a key first with: mk secrets key gen",
91
      keys_location
92
    );
93
  }
94

            
95
  let key_filename = format!("{key_name}.key");
96
  let key_path = keys_path.join(&key_filename);
97
  if !key_path.exists() || !key_path.is_file() {
98
    anyhow::bail!(
99
      "Key '{}' not found in '{}'. Generate it with: mk secrets key gen --name {}",
100
      key_name,
101
      keys_location,
102
      key_name
103
    );
104
  }
105

            
106
  Ok(())
107
}