use anyhow::{Context, Result};
use clap::Parser;
use serde::Serialize;
use twoken;
use twoken::otp::TOTP;
use twoken::store::{GenericStore, Store};
use twoken::token::{GenericToken, Token};
use twoken::yubikey::Yubikey;
static CLIPBOARD_TIMEOUT_SECONDS: f32 = 30.0;
#[derive(clap::ValueEnum, Default, Debug, Clone, Serialize)]
#[serde(rename_all = "kebab-case")]
enum TokenOption {
#[default]
Yubikey,
TOTP,
}
#[derive(Parser, Debug)]
#[command(version, about)]
struct Args {
token_id: String,
#[arg(short, long, default_value_t, value_enum)]
store: GenericStore,
#[arg(short, long, default_value_t, value_enum)]
token: TokenOption,
#[arg(short, long, default_value_t = false)]
print: bool,
#[arg(short, long, default_value_t = false)]
new: bool,
}
fn main() -> Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("warn"));
let args = Args::parse();
let mut store = args.store;
if args.new {
let token: twoken::token::GenericToken = match args.token {
TokenOption::Yubikey => GenericToken::Yubikey(Yubikey::default()),
TokenOption::TOTP => GenericToken::TOTP(TOTP::default()),
};
store
.put(&args.token_id, token)
.context("Could not store generated token in password store")?;
return Ok(());
}
let token_error = format!("Could not retrieve token: {:?}", args.token_id);
let token = match args.token {
TokenOption::Yubikey => {
GenericToken::Yubikey(store.get::<Yubikey>(&args.token_id).context(token_error)?)
}
TokenOption::TOTP => {
GenericToken::TOTP(store.get::<TOTP>(&args.token_id).context(token_error)?)
}
};
let password = token.generate_password();
match token {
GenericToken::Yubikey(mut key) => {
key.usage_counter += 1;
store
.put(&args.token_id, key)
.context(format!("Could not store token: {:?}", args.token_id))?;
}
_ => {}
};
if args.print {
println!("{}", password);
} else {
println!(
"Copying password to clipboard, will clear in {:.0} seconds. Press Ctrl-c to clear now.",
CLIPBOARD_TIMEOUT_SECONDS
);
twoken::clipboard::set_and_clear_clipboard(&password, CLIPBOARD_TIMEOUT_SECONDS)
.context("Could not copy password to clipboard")?;
}
Ok(())
}