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