use clap::{SubCommand, Arg, ArgMatches};
use error::{ErrorKind, Error};
use commands::{BasicOptions, StaticSubcommand};
use std::io::{Write,stderr};
use std::process::exit;
use meta;
use meta::KeyType;
use base64::{encode_config, URL_SAFE_NO_PAD};
pub fn invocation() -> StaticSubcommand {
return SubCommand::with_name("keys")
.about("Manage signing and SSH keys")
.arg(Arg::with_name("repository")
.long("repository")
.help("The repository where to record, defaults to the current directory.")
.takes_value(true)
.required(false))
.arg(Arg::with_name("generate-signing-key")
.long("generate-signing")
.help("Generate a signing key.")
.takes_value(false)
.required(false))
.arg(Arg::with_name("sign")
.long("sign")
.help("Challenge to sign.")
.takes_value(true)
.required(false))
.arg(Arg::with_name("generate-SSH-key")
.long("generate-ssh")
.help("Generate an SSH key.")
.takes_value(false)
.required(false))
.arg(Arg::with_name("local")
.long("local")
.help("Save keys for this repository only")
.takes_value(false)
.required(false));
}
pub struct Params<'a> {
pub generate_signing_key: bool,
pub generate_ssh_key: bool,
pub challenge: Option<&'a str>,
pub local: bool,
}
pub fn parse_args<'a>(args: &'a ArgMatches) -> Params<'a> {
Params {
generate_signing_key: args.is_present("generate-signing-key"),
generate_ssh_key: args.is_present("generate-SSH-key"),
challenge: args.value_of("sign"),
local: args.is_present("local"),
}
}
pub fn run(arg_matches: &ArgMatches) -> Result<(), Error> {
let opts = BasicOptions::from_args(arg_matches)?;
let args = parse_args(arg_matches);
let dot_pijul = if args.local {
Some(opts.repo_dir())
} else {
None
};
if args.generate_signing_key {
if let Some(ref dot_pijul) = dot_pijul {
meta::generate_key(&dot_pijul, KeyType::Signing)?
} else {
meta::generate_global_key(KeyType::Signing)?
}
}
if let Some(ref challenge) = args.challenge {
match meta::load_global_or_local_key(dot_pijul.as_ref(), KeyType::Signing) {
Ok(key) => {
let sig = key.sign(challenge.as_bytes());
println!("{}", encode_config(&sig, URL_SAFE_NO_PAD))
}
Err(e) => {
panic!("Could not find key: {:?}", e)
}
}
}
if args.generate_ssh_key {
if let Some(ref dot_pijul) = dot_pijul {
meta::generate_key(&dot_pijul, KeyType::SSH)?
} else {
meta::generate_global_key(KeyType::SSH)?
}
}
Ok(())
}
pub fn explain(r: Result<(), Error>) {
if let Err(Error(kind, _)) = r {
if let ErrorKind::InARepository(p) = kind {
writeln!(stderr(), "Repository {} already exists", p.display()).unwrap();
} else {
writeln!(stderr(), "error: {}", kind).unwrap();
}
exit(1)
}
}