use std::fmt;
use derive_deftly::Deftly;
use derive_more::Constructor;
use derive_more::derive::{From, Into};
use tor_error::Bug;
use tor_keymgr::{
InvalidKeyPathComponentValue, KeySpecifier, KeySpecifierComponent,
derive_deftly_template_CertSpecifier, derive_deftly_template_KeySpecifier,
};
use tor_persist::slug::{Slug, timestamp::Iso8601TimeSlug};
use web_time_compat::SystemTime;
#[non_exhaustive]
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KS_relayid_ed")]
#[deftly(summary = "Relay long-term identity keypair")]
pub(crate) struct RelayIdentityKeypairSpecifier;
#[non_exhaustive]
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KP_relayid_ed")]
#[deftly(summary = "Public part of the relay long-term identity keypair")]
pub(crate) struct RelayIdentityPublicKeySpecifier;
#[non_exhaustive]
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KS_relayid_rsa")]
#[deftly(summary = "Legacy RSA long-term relay identity keypair")]
pub(crate) struct RelayIdentityRsaKeypairSpecifier;
#[non_exhaustive]
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KP_relayid_rsa")]
#[deftly(summary = "Public part of the relay long-term identity keypair")]
pub(crate) struct RelayIdentityRsaPublicKeySpecifier;
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KS_relaysign_ed")]
#[deftly(summary = "Relay medium-term signing keypair")]
pub(crate) struct RelaySigningKeypairSpecifier {
#[deftly(denotator)]
pub(crate) valid_until: Timestamp,
}
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KP_relaysign_ed")]
#[deftly(summary = "Public part of the relay medium-term signing keypair")]
#[deftly(keypair_specifier = RelaySigningKeypairSpecifier)]
pub(crate) struct RelaySigningPublicKeySpecifier {
#[deftly(denotator)]
pub(crate) valid_until: Timestamp,
}
impl From<&RelaySigningPublicKeySpecifier> for RelaySigningKeypairSpecifier {
fn from(public_key_specifier: &RelaySigningPublicKeySpecifier) -> RelaySigningKeypairSpecifier {
RelaySigningKeypairSpecifier::new(public_key_specifier.valid_until)
}
}
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KS_ntor")]
#[deftly(summary = "Relay medium-term ntor keypair")]
pub(crate) struct RelayNtorKeypairSpecifier {
#[deftly(denotator)]
pub(crate) valid_until: Timestamp,
}
#[derive(Deftly, PartialEq, Debug, Constructor, Copy, Clone)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KP_ntor")]
#[deftly(summary = "Public part of the relay medium-term ntor keypair")]
#[deftly(keypair_specifier = RelayNtorKeypairSpecifier)]
pub(crate) struct RelayNtorPublicKeySpecifier {
#[deftly(denotator)]
pub(crate) valid_until: Timestamp,
}
impl From<&RelayNtorPublicKeySpecifier> for RelayNtorKeypairSpecifier {
fn from(public_key_specifier: &RelayNtorPublicKeySpecifier) -> RelayNtorKeypairSpecifier {
RelayNtorKeypairSpecifier::new(public_key_specifier.valid_until)
}
}
#[derive(Deftly, Constructor)]
#[derive_deftly(CertSpecifier)]
pub(crate) struct RelaySigningKeyCertSpecifier {
#[deftly(subject)]
subject: RelaySigningPublicKeySpecifier,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Into, From)]
pub(crate) struct Timestamp(Iso8601TimeSlug);
impl From<SystemTime> for Timestamp {
fn from(t: SystemTime) -> Self {
Self(t.into())
}
}
impl From<Timestamp> for SystemTime {
fn from(t: Timestamp) -> Self {
t.0.into()
}
}
impl KeySpecifierComponent for Timestamp {
fn to_slug(&self) -> Result<Slug, Bug> {
self.0.try_into()
}
fn from_slug(s: &Slug) -> Result<Self, InvalidKeyPathComponentValue>
where
Self: Sized,
{
use std::str::FromStr as _;
let timestamp = Iso8601TimeSlug::from_str(s.as_ref())
.map_err(|e| InvalidKeyPathComponentValue::Slug(e.to_string()))?;
Ok(Self(timestamp))
}
fn fmt_pretty(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
#[derive(Deftly, PartialEq, Debug, Constructor)]
#[derive_deftly(KeySpecifier)]
#[deftly(prefix = "relay")]
#[deftly(role = "KS_link_ed")]
#[deftly(summary = "Relay short-term link authentication keypair")]
pub(crate) struct RelayLinkSigningKeypairSpecifier {
#[deftly(denotator)]
pub(crate) valid_until: Timestamp,
}
#[cfg(test)]
mod test {
#![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 super::*;
use tor_keymgr::test_utils::check_key_specifier;
use tor_keymgr::{CertSpecifierPattern, KeyCertificateSpecifier, KeyPathPattern};
#[test]
fn relay_signing_key_specifiers() {
let ts = SystemTime::UNIX_EPOCH;
let key_spec = RelaySigningKeypairSpecifier::new(ts.into());
assert_eq!(
key_spec.arti_path().unwrap().as_str(),
"relay/ks_relaysign_ed+19700101000000"
);
check_key_specifier(&key_spec, "relay/ks_relaysign_ed+19700101000000");
let pubkey_spec = RelaySigningPublicKeySpecifier::new(ts.into());
assert_eq!(
pubkey_spec.arti_path().unwrap().as_str(),
"relay/kp_relaysign_ed+19700101000000"
);
check_key_specifier(&pubkey_spec, "relay/kp_relaysign_ed+19700101000000");
let cert_spec = RelaySigningKeyCertSpecifier {
subject: pubkey_spec,
};
assert_eq!(
cert_spec.subject_key_specifier().arti_path().unwrap(),
pubkey_spec.arti_path().unwrap()
);
assert_eq!(
RelaySigningKeyCertSpecifierPattern::new_any()
.arti_pattern()
.unwrap(),
KeyPathPattern::Arti("relay/kp_relaysign_ed+*".to_string())
);
}
#[test]
fn relay_identity_key_specifiers() {
let key_spec = RelayIdentityKeypairSpecifier::new();
assert_eq!(
key_spec.arti_path().unwrap().as_str(),
"relay/ks_relayid_ed"
);
check_key_specifier(&key_spec, "relay/ks_relayid_ed");
let key_spec = RelayIdentityPublicKeySpecifier::new();
assert_eq!(
key_spec.arti_path().unwrap().as_str(),
"relay/kp_relayid_ed"
);
check_key_specifier(&key_spec, "relay/kp_relayid_ed");
}
}