use clap::Parser;
use rpassword::read_password_from_tty;
extern crate keyring;
use keyring::{Entry, Error};
#[derive(Debug, Parser)]
#[clap(author = "github.com/hwchen/keyring-rs")]
pub struct Cli {
#[clap(short, action = clap::ArgAction::Count)]
pub verbose: u8,
#[clap(short, long, value_parser)]
pub target: Option<String>,
#[clap(short, long, value_parser, default_value = "keyring-cli")]
pub service: String,
#[clap(short, long, value_parser)]
pub username: Option<String>,
#[clap(subcommand)]
pub command: Command,
}
#[derive(Debug, Parser)]
pub enum Command {
Set {
#[clap(value_parser)]
password: Option<String>,
},
Get,
Delete,
}
fn main() {
let args: Cli = Cli::parse();
execute_args(&args);
}
fn execute_args(args: &Cli) {
let username = if let Some(username) = &args.username {
username.clone()
} else {
whoami::username()
};
let entry = if let Some(target) = args.target.as_ref() {
Entry::new_with_target(target, &args.service, &username)
} else {
Entry::new(&args.service, &username)
};
match &args.command {
Command::Set {
password: Some(password),
} => execute_set_password(&username, args.verbose, &entry, password),
Command::Set { password: None } => {
if let Ok(password) = read_password_from_tty(Some("Password: ")) {
execute_set_password(&username, args.verbose, &entry, &password)
} else {
eprintln!("(Failed to read password, so none set.)")
}
}
Command::Get => execute_get_password_and_credential(&username, args.verbose, &entry),
Command::Delete => execute_delete_password(&username, args.verbose, &entry),
}
}
fn execute_set_password(username: &str, verbose: u8, entry: &Entry, password: &str) {
match entry.set_password(password) {
Ok(()) => println!("(Password for user '{}' set successfully)", username),
Err(err) => {
eprintln!("Couldn't set password for user '{}': {}", username, err);
if verbose > 1 {
eprintln!("Error details: {:?}", err);
}
}
}
}
fn execute_get_password_and_credential(username: &str, verbose: u8, entry: &Entry) {
match entry.get_password_and_credential() {
Ok((password, credential)) => {
println!("The password for user '{}' is '{}'", username, &password);
if verbose > 0 {
println!("Credential is: {:?}", credential)
}
}
Err(Error::NoEntry) => {
eprintln!("(No password found for user '{}')", username);
if verbose > 1 {
eprintln!("Error details: {:?}", Error::NoEntry);
}
}
Err(err) => {
eprintln!("Couldn't get password for user '{}': {}", username, err);
if verbose > 1 {
eprintln!("Error details: {:?}", err);
}
}
}
}
fn execute_delete_password(username: &str, verbose: u8, entry: &Entry) {
match entry.delete_password() {
Ok(()) => println!("(Password for user '{}' deleted)", username),
Err(Error::NoEntry) => {
eprintln!("(No password for user '{}' found)", username);
if verbose > 1 {
eprintln!("Error details: {:?}", Error::NoEntry);
}
}
Err(err) => {
eprintln!("Couldn't delete password for user '{}': {}", username, err);
if verbose > 1 {
eprintln!("Error details: {:?}", err);
}
}
}
}