use clap::{Args, Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Debug, Parser)]
#[command(name = "sefy", version, about, long_about = None)]
pub struct Cli {
#[arg(
long,
short = 'f',
global = true,
env = "SEFY_VAULT",
value_name = "FILE"
)]
pub vault: Option<PathBuf>,
#[arg(long, global = true, value_name = "VAR")]
pub password_env: Option<String>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Init,
Add {
#[command(subcommand)]
kind: AddKind,
},
Get(GetArgs),
Show {
reference: String,
},
Ls(ListArgs),
Find(FindArgs),
Edit(EditArgs),
Rm {
reference: String,
#[arg(long, short = 'y')]
yes: bool,
},
Extract {
reference: String,
#[arg(long, short = 'o', value_name = "PATH")]
output: Option<PathBuf>,
#[arg(long)]
force: bool,
},
Tags,
Export {
#[arg(long, short = 'o', value_name = "PATH")]
output: Option<PathBuf>,
#[arg(long)]
i_know_this_writes_plaintext: bool,
#[arg(long)]
force: bool,
},
Import {
#[arg(value_name = "PATH")]
input: Option<PathBuf>,
},
Merge {
#[arg(value_name = "FILE")]
other: PathBuf,
#[arg(long, value_name = "VAR")]
other_password_env: Option<String>,
},
ChangePassword {
#[arg(long, value_name = "VAR")]
new_password_env: Option<String>,
},
Plugin {
#[command(subcommand)]
action: PluginAction,
},
Completions {
shell: clap_complete::Shell,
},
}
#[derive(Debug, Subcommand)]
pub enum PluginAction {
List {
#[arg(long)]
paths: bool,
},
}
#[derive(Debug, Subcommand)]
pub enum AddKind {
Note {
title: String,
#[arg(long, short = 't', conflicts_with = "editor")]
text: Option<String>,
#[arg(long, short = 'e')]
editor: bool,
#[arg(long, value_delimiter = ',')]
tag: Vec<String>,
},
Credential {
title: String,
#[arg(long, short = 'l')]
login: String,
#[arg(long, short = 'u')]
url: Option<String>,
#[arg(long)]
totp: Option<String>,
#[arg(long)]
notes: Option<String>,
#[arg(long = "item-password-env", value_name = "VAR")]
item_password_env: Option<String>,
#[arg(long, value_delimiter = ',')]
tag: Vec<String>,
},
File {
path: PathBuf,
#[arg(long, short = 'T')]
title: Option<String>,
#[arg(long, value_delimiter = ',')]
tag: Vec<String>,
},
}
#[derive(Debug, Args)]
pub struct GetArgs {
pub reference: String,
#[arg(long, value_enum, default_value_t = Field::Password)]
pub field: Field,
#[arg(long)]
pub stdout: bool,
#[arg(long, value_name = "SECONDS", default_value_t = 45)]
pub clear_after: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum Field {
Password,
Login,
Url,
Totp,
}
impl Field {
pub fn as_str(self) -> &'static str {
match self {
Self::Password => "password",
Self::Login => "login",
Self::Url => "url",
Self::Totp => "totp",
}
}
}
#[derive(Debug, Args)]
pub struct ListArgs {
#[arg(long, value_enum)]
pub kind: Option<Kind>,
#[arg(long, value_delimiter = ',')]
pub tag: Vec<String>,
}
#[derive(Debug, Args)]
pub struct FindArgs {
pub text: Option<String>,
#[arg(long, value_enum)]
pub kind: Option<Kind>,
#[arg(long, value_delimiter = ',')]
pub tag: Vec<String>,
}
#[derive(Debug, Args)]
pub struct EditArgs {
pub reference: String,
#[arg(long)]
pub title: Option<String>,
#[arg(long, short = 't', conflicts_with = "editor")]
pub text: Option<String>,
#[arg(long, short = 'e')]
pub editor: bool,
#[arg(long, short = 'l')]
pub login: Option<String>,
#[arg(long)]
pub password: bool,
#[arg(
long = "item-password-env",
value_name = "VAR",
conflicts_with = "password"
)]
pub item_password_env: Option<String>,
#[arg(long, short = 'u')]
pub url: Option<String>,
#[arg(long)]
pub totp: Option<String>,
#[arg(long)]
pub notes: Option<String>,
#[arg(long, value_delimiter = ',')]
pub tag: Vec<String>,
#[arg(long, conflicts_with = "tag")]
pub clear_tags: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum Kind {
Note,
Credential,
File,
}
impl From<Kind> for sefy_core::ItemKind {
fn from(kind: Kind) -> Self {
match kind {
Kind::Note => Self::Note,
Kind::Credential => Self::Credential,
Kind::File => Self::File,
}
}
}