use anyhow::{Result, bail};
use bc_components::{
PublicKeys, Signature, SigningPrivateKey, SigningPublicKey,
};
use bc_envelope::prelude::*;
use clap::Args;
use ssh_key::LineEnding;
use super::{ASKPASS_HELP, ASKPASS_LONG_HELP};
use crate::{read_argument, read_password};
#[derive(Debug, Args)]
#[group(skip)]
pub struct CommandArgs {
ur_string: Option<String>,
#[arg(long, default_value = "false")]
encrypt: bool,
#[arg(long)]
password: Option<String>,
#[arg(long, requires = "encrypt", help = ASKPASS_HELP, long_help = ASKPASS_LONG_HELP)]
askpass: bool,
}
impl crate::Exec for CommandArgs {
fn exec(&self) -> Result<String> {
let object = read_argument(self.ur_string.as_deref())?;
if let Ok(signing_private_key) =
SigningPrivateKey::from_ur_string(&object)
{
if let Some(ssh_private_key) = signing_private_key.to_ssh() {
if self.encrypt {
let mut rng = rand::rngs::OsRng;
let password = read_password(
"Key encryption password: ",
self.password.as_deref(),
self.askpass,
)?;
let openssh = ssh_private_key
.encrypt(&mut rng, password)?
.to_openssh(LineEnding::LF)?;
Ok(openssh.trim().to_string())
} else {
Ok(ssh_private_key
.to_openssh(LineEnding::LF)?
.trim()
.to_string())
}
} else {
bail!("UR is not an SSH private key.");
}
} else if let Ok(signing_public_key) =
SigningPublicKey::from_ur_string(&object)
{
if let Some(ssh_public_key) = signing_public_key.to_ssh() {
Ok(ssh_public_key.to_openssh()?.to_string())
} else {
bail!("UR is not an SSH public key.");
}
} else if let Ok(public_keys) = PublicKeys::from_ur_string(&object) {
if let Some(ssh_public_key) =
public_keys.signing_public_key().to_ssh()
{
Ok(ssh_public_key.to_openssh()?.to_string())
} else {
bail!("UR is not a PublicKeys with an SSH public key.");
}
} else if let Ok(signature) = Signature::from_ur_string(&object) {
if let Some(ssh_signature) = signature.to_ssh() {
Ok(ssh_signature.to_pem(LineEnding::LF)?.trim().to_string())
} else {
bail!("UR is not an SSH signature.");
}
} else {
bail!(
"Invalid object for export. Supported types are SSH `ur:signing-private-key`, SSH `ur:signing-public-key`, SSH `ur:crypto-pubkeys`, and `ur:signature`."
);
}
}
}