use std::ffi::OsString;
use clap::{
Parser,
error::{ContextKind, ContextValue, ErrorKind},
};
use cosmian_kms_client::{
KmsClient,
cosmian_kmip::kmip_2_1::kmip_types::{CryptographicAlgorithm, KeyFormatType},
kmip_2_1::{kmip_objects::ObjectType, kmip_types::UniqueIdentifier},
reexport::cosmian_kms_client_utils::locate_utils::build_locate_request,
};
use strum::IntoEnumIterator;
use crate::{actions::kms::console, error::result::KmsCliResult};
#[derive(Parser, Default, Debug)]
#[clap(verbatim_doc_comment)]
pub struct LocateObjectsAction {
#[clap(long = "tag", short = 't', value_name = "TAG", verbatim_doc_comment)]
pub(crate) tags: Option<Vec<String>>,
#[clap(
long = "algorithm",
short = 'a',
value_parser = CryptographicAlgorithmParser,
verbatim_doc_comment
)]
pub(crate) cryptographic_algorithm: Option<CryptographicAlgorithm>,
#[clap(long = "cryptographic-length", short = 'l')]
pub(crate) cryptographic_length: Option<i32>,
#[clap(long = "key-format-type", short = 'f',
value_parser = KeyFormatTypeParser,verbatim_doc_comment)]
pub(crate) key_format_type: Option<KeyFormatType>,
#[clap(long, short = 'o',
value_parser = ObjectTypeParser,verbatim_doc_comment)]
pub(crate) object_type: Option<ObjectType>,
#[clap(long, short = 'p')]
pub(crate) public_key_id: Option<String>,
#[clap(long, short = 'k')]
pub(crate) private_key_id: Option<String>,
#[clap(long = "certificate-id", short = 'c')]
pub(crate) certificate_id: Option<String>,
}
impl LocateObjectsAction {
pub async fn run(&self, kms_rest_client: KmsClient) -> KmsCliResult<Vec<UniqueIdentifier>> {
let request = build_locate_request(
kms_rest_client.config.vendor_id.as_str(),
self.tags.clone(),
self.cryptographic_algorithm,
self.cryptographic_length,
self.key_format_type,
self.object_type,
self.public_key_id.as_deref(),
self.private_key_id.as_deref(),
self.certificate_id.as_deref(),
)?;
let response = kms_rest_client.locate(request).await?;
if let Some(ids) = response.unique_identifier {
if ids.is_empty() {
console::Stdout::new("No object found.").write()?;
} else {
let mut stdout = console::Stdout::new("List of unique identifiers:");
stdout.set_unique_identifiers(&ids);
stdout.write()?;
}
return Ok(ids);
}
console::Stdout::new("No object found.").write()?;
Ok(vec![])
}
}
#[derive(Clone)]
struct CryptographicAlgorithmParser;
impl clap::builder::TypedValueParser for CryptographicAlgorithmParser {
type Value = CryptographicAlgorithm;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
CryptographicAlgorithm::iter()
.find(|algo| {
OsString::from(algo.to_string().to_lowercase()) == value.to_ascii_lowercase()
})
.ok_or_else(|| {
let mut err = clap::Error::new(ErrorKind::ValueValidation).with_cmd(cmd);
if let Some(arg) = arg {
err.insert(
ContextKind::InvalidArg,
ContextValue::String(arg.to_string()),
);
}
err.insert(
ContextKind::InvalidValue,
ContextValue::String(value.to_string_lossy().to_string()),
);
err.insert(
ContextKind::SuggestedValue,
ContextValue::Strings(
CryptographicAlgorithm::iter()
.map(|algo| algo.to_string())
.collect::<Vec<String>>(),
),
);
err
})
}
}
#[derive(Clone)]
struct KeyFormatTypeParser;
impl clap::builder::TypedValueParser for KeyFormatTypeParser {
type Value = KeyFormatType;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
KeyFormatType::iter()
.find(|algo| {
OsString::from(algo.to_string().to_lowercase()) == value.to_ascii_lowercase()
})
.ok_or_else(|| {
let mut err = clap::Error::new(ErrorKind::ValueValidation).with_cmd(cmd);
if let Some(arg) = arg {
err.insert(
ContextKind::InvalidArg,
ContextValue::String(arg.to_string()),
);
}
err.insert(
ContextKind::InvalidValue,
ContextValue::String(value.to_string_lossy().to_string()),
);
err.insert(
ContextKind::SuggestedValue,
ContextValue::Strings(
KeyFormatType::iter()
.map(|algo| algo.to_string())
.collect::<Vec<String>>(),
),
);
err
})
}
}
#[derive(Clone)]
struct ObjectTypeParser;
impl clap::builder::TypedValueParser for ObjectTypeParser {
type Value = ObjectType;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::Error> {
ObjectType::iter()
.find(|object_type| {
OsString::from(object_type.to_string().to_lowercase()) == value.to_ascii_lowercase()
})
.ok_or_else(|| {
let mut err = clap::Error::new(ErrorKind::ValueValidation).with_cmd(cmd);
if let Some(arg) = arg {
err.insert(
ContextKind::InvalidArg,
ContextValue::String(arg.to_string()),
);
}
err.insert(
ContextKind::InvalidValue,
ContextValue::String(value.to_string_lossy().to_string()),
);
err.insert(
ContextKind::SuggestedValue,
ContextValue::Strings(
ObjectType::iter()
.map(|object_type| object_type.to_string())
.collect::<Vec<String>>(),
),
);
err
})
}
}