1use anyhow::Result;
2use clap::{Parser, Subcommand};
3
4use std::path::PathBuf;
5
6mod crypto;
7
8#[derive(Parser)]
9#[command(name = "teal")]
10#[command(about = "Teal management utilities")]
11#[command(version = "0.1.0")]
12struct Cli {
13 #[command(subcommand)]
14 command: Commands,
15}
16
17#[derive(Subcommand)]
18enum Commands {
19 /// Generate a new K256 key pair
20 GenKey {
21 /// Key name/identifier
22 #[arg(short, long, default_value = "repo")]
23 name: String,
24
25 /// Output directory (defaults to ~/.teal/keys)
26 #[arg(short, long)]
27 output: Option<PathBuf>,
28
29 /// Overwrite existing keys
30 #[arg(short, long)]
31 force: bool,
32
33 /// Output format: json, multibase, or files
34 #[arg(long, default_value = "files")]
35 format: String,
36 },
37
38 /// Extract public key multibase from private key
39 ExtractPubkey {
40 /// Path to private key file
41 #[arg(short, long)]
42 private_key: PathBuf,
43
44 /// Output format
45 #[arg(short, long, default_value = "multibase")]
46 format: String,
47 },
48
49 /// List available keys
50 List {
51 /// Keys directory (defaults to ~/.teal/keys)
52 #[arg(short, long)]
53 directory: Option<PathBuf>,
54 },
55
56 /// Rotate keys (generate new, backup old)
57 Rotate {
58 /// Key name to rotate
59 #[arg(short, long)]
60 name: String,
61
62 /// Backup directory
63 #[arg(short, long)]
64 backup_dir: Option<PathBuf>,
65 },
66}
67
68fn get_default_keys_dir() -> PathBuf {
69 dirs::home_dir()
70 .unwrap_or_else(|| PathBuf::from("."))
71 .join(".teal")
72 .join("keys")
73}
74
75#[tokio::main]
76async fn main() -> Result<()> {
77 let cli = Cli::parse();
78
79 match cli.command {
80 Commands::GenKey {
81 name,
82 output,
83 force,
84 format,
85 } => {
86 let keys_dir = output.unwrap_or_else(get_default_keys_dir);
87 crypto::generate_key(name, keys_dir, force, format).await
88 }
89 Commands::ExtractPubkey {
90 private_key,
91 format,
92 } => crypto::extract_pubkey(private_key, format).await,
93 Commands::List { directory } => {
94 let keys_dir = directory.unwrap_or_else(get_default_keys_dir);
95 crypto::list_keys(keys_dir).await
96 }
97 Commands::Rotate { name, backup_dir } => {
98 let keys_dir = get_default_keys_dir();
99 crypto::rotate_key(keys_dir, name, backup_dir).await
100 }
101 }
102}