1#![allow(clippy::bool_assert_comparison)]
5#![allow(clippy::clone_on_copy)]
6#![allow(clippy::dbg_macro)]
7#![allow(clippy::mixed_attributes_style)]
8#![allow(clippy::print_stderr)]
9#![allow(clippy::print_stdout)]
10#![allow(clippy::single_char_pattern)]
11#![allow(clippy::unwrap_used)]
12#![allow(clippy::unchecked_time_subtraction)]
13#![allow(clippy::useless_vec)]
14#![allow(clippy::needless_pass_by_value)]
15#![allow(clippy::string_slice)] use std::fmt::Debug;
19
20use crate::{ArtiPath, KeyPath, KeySpecifier};
21
22#[cfg(test)]
28use {
29 std::io::Error,
30 std::io::ErrorKind::{Interrupted, NotFound},
31 std::process::{Command, Stdio},
32 tempfile::tempdir,
33};
34
35pub fn check_key_specifier<S, E>(spec: &S, path: &str)
41where
42 S: KeySpecifier + Debug + PartialEq,
43 S: for<'p> TryFrom<&'p KeyPath, Error = E>,
44 E: Debug,
45{
46 let apath = ArtiPath::new(path.to_string()).unwrap();
47 assert_eq!(spec.arti_path().unwrap(), apath);
48 assert_eq!(&S::try_from(&KeyPath::Arti(apath)).unwrap(), spec, "{path}");
49}
50
51#[cfg(test)]
63pub(crate) fn sshkeygen_ed25519_strings() -> std::io::Result<(String, String)> {
64 let tempdir = tempdir()?;
65 const FILENAME: &str = "tmp_id_ed25519";
66 let status = Command::new("ssh-keygen")
67 .current_dir(tempdir.path())
68 .stdout(Stdio::null())
69 .stderr(Stdio::null())
70 .args(["-q", "-P", "", "-t", "ed25519", "-f", FILENAME, "-C", ""])
71 .status()
72 .map_err(|e| match e.kind() {
73 NotFound => Error::new(NotFound, "could not find ssh-keygen"),
74 _ => e,
75 })?;
76
77 match status.code() {
78 Some(0) => {
79 let key = tempdir.path().join(FILENAME);
80 let key_pub = key.with_extension("pub");
81
82 let key = std::fs::read_to_string(key)?;
83 let key_pub = std::fs::read_to_string(key_pub)?;
84
85 Ok((key, key_pub))
86 }
87 Some(code) => Err(Error::other(format!(
88 "ssh-keygen exited with status code: {code}"
89 ))),
90 None => Err(Error::new(
91 Interrupted,
92 "ssh-keygen was terminated by a signal",
93 )),
94 }
95}
96
97#[cfg(test)]
99pub(crate) mod ssh_keys {
100 macro_rules! define_key_consts {
116 (
117 PUB => { $($(#[ $docs_and_attrs:meta ])* $basename:literal,)* },
118 PRIV => { $($(#[ $docs_and_attrs_priv:meta ])* $basename_priv:literal,)* }
119 ) => {
120 $(
121 paste::paste! {
122 define_key_consts!(
123 @ $(#[ $docs_and_attrs ])*
124 [< $basename:upper _PUB >], $basename, ".public"
125 );
126 }
127 )*
128
129 $(
130 paste::paste! {
131 define_key_consts!(
132 @ $(#[ $docs_and_attrs_priv ])*
133 [< $basename_priv:upper >], $basename_priv, ".private"
134 );
135 }
136 )*
137 };
138
139 (
140 @ $($(#[ $docs_and_attrs:meta ])*
141 $const_name:ident, $basename:literal, $extension:literal)*
142 ) => {
143 $(
144 $(#[ $docs_and_attrs ])*
145 pub(crate) const $const_name: &str =
146 include_str!(concat!("../testdata/", $basename, $extension));
147 )*
148 }
149 }
150
151 define_key_consts! {
152 PUB => {
154 "ed25519_openssh",
156 "ed25519_openssh_bad",
158 "ed25519_expanded_openssh",
162 "x25519_openssh",
164 "x25519_openssh_unknown_algorithm",
166 },
167 PRIV => {
169 "ed25519_openssh",
171 "ed25519_openssh_bad",
173 "ed25519_expanded_openssh",
175 "ed25519_expanded_openssh_bad",
177 "dsa_openssh",
179 "x25519_openssh",
181 "x25519_openssh_unknown_algorithm",
183 }
184 }
185}
186
187#[cfg(test)]
189mod specifier {
190 #[cfg(feature = "experimental-api")]
191 use crate::key_specifier::derive::derive_deftly_template_CertSpecifier;
192 use crate::key_specifier::derive::derive_deftly_template_KeySpecifier;
193 use crate::{ArtiPath, ArtiPathUnavailableError, CTorPath, KeySpecifier};
194
195 use derive_deftly::Deftly;
196
197 pub(crate) const TEST_SPECIFIER_PATH: &str = "parent1/parent2/parent3/test-specifier";
199
200 #[derive(Default, PartialEq, Eq)]
204 pub(crate) struct TestSpecifier(String);
205
206 impl TestSpecifier {
207 pub(crate) fn new(suffix: impl AsRef<str>) -> Self {
209 Self(suffix.as_ref().into())
210 }
211 }
212
213 impl KeySpecifier for TestSpecifier {
214 fn arti_path(&self) -> Result<ArtiPath, ArtiPathUnavailableError> {
215 Ok(ArtiPath::new(format!("{TEST_SPECIFIER_PATH}{}", self.0))
216 .map_err(|e| tor_error::internal!("{e}"))?)
217 }
218
219 fn ctor_path(&self) -> Option<CTorPath> {
220 None
221 }
222
223 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
224 None
225 }
226 }
227
228 #[derive(Debug, Clone)]
230 pub(crate) struct TestCTorSpecifier(pub(crate) CTorPath);
231
232 impl KeySpecifier for TestCTorSpecifier {
233 fn arti_path(&self) -> Result<ArtiPath, ArtiPathUnavailableError> {
234 unimplemented!()
235 }
236
237 fn ctor_path(&self) -> Option<CTorPath> {
238 Some(self.0.clone())
239 }
240
241 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
242 unimplemented!()
243 }
244 }
245
246 #[derive(Deftly)]
248 #[derive_deftly(KeySpecifier)]
249 #[deftly(prefix = "test")]
250 #[deftly(role = "simple_keypair")]
251 #[deftly(summary = "A test keypair specifier")]
252 pub(crate) struct TestDerivedKeypairSpecifier;
253
254 impl From<&TestDerivedKeySpecifier> for TestDerivedKeypairSpecifier {
255 fn from(_: &TestDerivedKeySpecifier) -> Self {
256 Self
257 }
258 }
259
260 #[derive(Deftly)]
262 #[derive_deftly(KeySpecifier)]
263 #[deftly(prefix = "test")]
264 #[deftly(role = "simple_key")]
265 #[deftly(summary = "A test key specifier")]
266 #[deftly(keypair_specifier = TestDerivedKeypairSpecifier)]
267 pub(crate) struct TestDerivedKeySpecifier;
268
269 #[derive(Deftly)]
271 #[derive_deftly(CertSpecifier)]
272 #[cfg(feature = "experimental-api")]
273 pub(crate) struct TestCertSpecifier {
274 #[deftly(subject)]
276 pub(crate) subject_key_spec: TestDerivedKeySpecifier,
277 #[deftly(denotator)]
279 pub(crate) denotator: String,
280 }
281}
282
283#[cfg(test)]
285mod key {
286 use crate::EncodableItem;
287 use tor_key_forge::{ItemType, KeystoreItem, KeystoreItemType};
288
289 pub(crate) struct DummyKey;
295
296 impl ItemType for DummyKey {
297 fn item_type() -> KeystoreItemType
298 where
299 Self: Sized,
300 {
301 todo!()
302 }
303 }
304
305 impl EncodableItem for DummyKey {
306 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
307 todo!()
308 }
309 }
310}
311
312#[cfg(test)]
313pub(crate) use specifier::*;
314
315#[cfg(test)]
316pub(crate) use key::*;
317
318#[cfg(test)]
319pub(crate) use internal::assert_found;
320
321#[cfg(test)]
323mod internal {
324 macro_rules! assert_found {
326 ($key_store:expr, $key_spec:expr, $key_type:expr, $found:expr) => {{
327 let res = $key_store
328 .get($key_spec, &$key_type.clone().into())
329 .unwrap();
330 if $found {
331 assert!(res.is_some());
332 assert!(
334 $key_store
335 .contains($key_spec, &$key_type.clone().into())
336 .unwrap()
337 );
338 } else {
339 assert!(res.is_none());
340 }
341 }};
342 }
343
344 pub(crate) use assert_found;
345}