#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_time_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
use std::fmt::Debug;
use crate::{ArtiPath, KeyPath, KeySpecifier};
#[cfg(test)]
use {
std::io::Error,
std::io::ErrorKind::{Interrupted, NotFound},
std::process::{Command, Stdio},
tempfile::tempdir,
};
pub fn check_key_specifier<S, E>(spec: &S, path: &str)
where
S: KeySpecifier + Debug + PartialEq,
S: for<'p> TryFrom<&'p KeyPath, Error = E>,
E: Debug,
{
let apath = ArtiPath::new(path.to_string()).unwrap();
assert_eq!(spec.arti_path().unwrap(), apath);
assert_eq!(&S::try_from(&KeyPath::Arti(apath)).unwrap(), spec, "{path}");
}
#[cfg(test)]
pub(crate) fn sshkeygen_ed25519_strings() -> std::io::Result<(String, String)> {
let tempdir = tempdir()?;
const FILENAME: &str = "tmp_id_ed25519";
let status = Command::new("ssh-keygen")
.current_dir(tempdir.path())
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["-q", "-P", "", "-t", "ed25519", "-f", FILENAME, "-C", ""])
.status()
.map_err(|e| match e.kind() {
NotFound => Error::new(NotFound, "could not find ssh-keygen"),
_ => e,
})?;
match status.code() {
Some(0) => {
let key = tempdir.path().join(FILENAME);
let key_pub = key.with_extension("pub");
let key = std::fs::read_to_string(key)?;
let key_pub = std::fs::read_to_string(key_pub)?;
Ok((key, key_pub))
}
Some(code) => Err(Error::other(format!(
"ssh-keygen exited with status code: {code}"
))),
None => Err(Error::new(
Interrupted,
"ssh-keygen was terminated by a signal",
)),
}
}
#[cfg(test)]
pub(crate) mod ssh_keys {
macro_rules! define_key_consts {
(
PUB => { $($(#[ $docs_and_attrs:meta ])* $basename:literal,)* },
PRIV => { $($(#[ $docs_and_attrs_priv:meta ])* $basename_priv:literal,)* }
) => {
$(
paste::paste! {
define_key_consts!(
@ $(#[ $docs_and_attrs ])*
[< $basename:upper _PUB >], $basename, ".public"
);
}
)*
$(
paste::paste! {
define_key_consts!(
@ $(#[ $docs_and_attrs_priv ])*
[< $basename_priv:upper >], $basename_priv, ".private"
);
}
)*
};
(
@ $($(#[ $docs_and_attrs:meta ])*
$const_name:ident, $basename:literal, $extension:literal)*
) => {
$(
$(#[ $docs_and_attrs ])*
pub(crate) const $const_name: &str =
include_str!(concat!("../testdata/", $basename, $extension));
)*
}
}
define_key_consts! {
PUB => {
"ed25519_openssh",
"ed25519_openssh_bad",
"ed25519_expanded_openssh",
"x25519_openssh",
"x25519_openssh_unknown_algorithm",
},
PRIV => {
"ed25519_openssh",
"ed25519_openssh_bad",
"ed25519_expanded_openssh",
"ed25519_expanded_openssh_bad",
"dsa_openssh",
"x25519_openssh",
"x25519_openssh_unknown_algorithm",
}
}
}
#[cfg(test)]
mod specifier {
#[cfg(feature = "experimental-api")]
use crate::key_specifier::derive::derive_deftly_template_CertSpecifier;
use crate::key_specifier::derive::derive_deftly_template_KeySpecifier;
use crate::{ArtiPath, ArtiPathUnavailableError, CTorPath, KeySpecifier};
use derive_deftly::Deftly;
pub(crate) const TEST_SPECIFIER_PATH: &str = "parent1/parent2/parent3/test-specifier";
#[derive(Default, PartialEq, Eq)]
pub(crate) struct TestSpecifier(String);
impl TestSpecifier {
pub(crate) fn new(suffix: impl AsRef<str>) -> Self {
Self(suffix.as_ref().into())
}
}
impl KeySpecifier for TestSpecifier {
fn arti_path(&self) -> Result<ArtiPath, ArtiPathUnavailableError> {
Ok(ArtiPath::new(format!("{TEST_SPECIFIER_PATH}{}", self.0))
.map_err(|e| tor_error::internal!("{e}"))?)
}
fn ctor_path(&self) -> Option<CTorPath> {
None
}
fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
None
}
}
#[derive(Debug, Clone)]
pub(crate) struct TestCTorSpecifier(pub(crate) CTorPath);
impl KeySpecifier for TestCTorSpecifier {
fn arti_path(&self) -> Result<ArtiPath, ArtiPathUnavailableError> {
unimplemented!()
}
fn ctor_path(&self) -> Option<CTorPath> {
Some(self.0.clone())
}
fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
unimplemented!()
}
}
#[derive(Deftly)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "test")]
#[deftly(role = "simple_keypair")]
#[deftly(summary = "A test keypair specifier")]
pub(crate) struct TestDerivedKeypairSpecifier;
impl From<&TestDerivedKeySpecifier> for TestDerivedKeypairSpecifier {
fn from(_: &TestDerivedKeySpecifier) -> Self {
Self
}
}
#[derive(Deftly)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "test")]
#[deftly(role = "simple_key")]
#[deftly(summary = "A test key specifier")]
#[deftly(keypair_specifier = "TestDerivedKeypairSpecifier")]
pub(crate) struct TestDerivedKeySpecifier;
#[derive(Deftly)]
#[derive_deftly(CertSpecifier)]
#[cfg(feature = "experimental-api")]
pub(crate) struct TestCertSpecifier {
#[deftly(subject)]
pub(crate) subject_key_spec: TestDerivedKeySpecifier,
#[deftly(denotator)]
pub(crate) denotator: String,
}
}
#[cfg(test)]
mod key {
use crate::EncodableItem;
use tor_key_forge::{ItemType, KeystoreItem, KeystoreItemType};
pub(crate) struct DummyKey;
impl ItemType for DummyKey {
fn item_type() -> KeystoreItemType
where
Self: Sized,
{
todo!()
}
}
impl EncodableItem for DummyKey {
fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
todo!()
}
}
}
#[cfg(test)]
pub(crate) use specifier::*;
#[cfg(test)]
pub(crate) use key::*;
#[cfg(test)]
pub(crate) use internal::assert_found;
#[cfg(test)]
mod internal {
macro_rules! assert_found {
($key_store:expr, $key_spec:expr, $key_type:expr, $found:expr) => {{
let res = $key_store
.get($key_spec, &$key_type.clone().into())
.unwrap();
if $found {
assert!(res.is_some());
assert!(
$key_store
.contains($key_spec, &$key_type.clone().into())
.unwrap()
);
} else {
assert!(res.is_none());
}
}};
}
pub(crate) use assert_found;
}