use base64ct::{Base64Unpadded, Encoding as _};
use derive_deftly::Deftly;
use tor_config::derive::prelude::*;
use tor_config::{ConfigBuildError, define_list_builder_accessors, define_list_builder_helper};
use tor_llcrypto::pk::ed25519::Ed25519Identity;
use tor_llcrypto::pk::rsa::RsaIdentity;
use std::net::SocketAddr;
#[derive(Debug, Clone, Deftly, Eq, PartialEq)]
#[derive_deftly(TorConfig)]
#[deftly(tor_config(
no_default_trait,
post_build = "FallbackDirBuilder::post_build_validate"
))]
pub struct FallbackDir {
#[deftly(tor_config(no_default))]
rsa_identity: RsaIdentity,
#[deftly(tor_config(no_default))]
ed_identity: Ed25519Identity,
#[deftly(tor_config(no_magic, setter(skip), no_default))]
orports: Vec<SocketAddr>,
}
define_list_builder_accessors!(
struct FallbackDirBuilder {
pub orports: [SocketAddr],
}
);
impl FallbackDirBuilder {
fn post_build_validate(built: FallbackDir) -> Result<FallbackDir, ConfigBuildError> {
if built.orports.is_empty() {
return Err(ConfigBuildError::Invalid {
field: "orport".to_string(),
problem: "list was empty".to_string(),
});
}
Ok(built)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct FallbackList {
fallbacks: Vec<FallbackDir>,
}
impl<T: IntoIterator<Item = FallbackDir>> From<T> for FallbackList {
fn from(fallbacks: T) -> Self {
FallbackList {
fallbacks: fallbacks.into_iter().collect(),
}
}
}
define_list_builder_helper! {
pub struct FallbackListBuilder {
pub(crate) fallbacks: [FallbackDirBuilder],
}
built: FallbackList = FallbackList { fallbacks };
default = default_fallbacks();
}
impl FallbackList {
pub fn len(&self) -> usize {
self.fallbacks.len()
}
pub fn is_empty(&self) -> bool {
self.fallbacks.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<'_, FallbackDir> {
self.fallbacks.iter()
}
}
pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
let mut bld = FallbackDir::builder();
bld.rsa_identity(rsa).ed_identity(ed);
ports
.iter()
.map(|s| s.parse().expect("Bad socket address in fallbacklist"))
.for_each(|p| {
bld.orports().push(p);
});
bld
}
include!("../data/fallback_dirs.rs")
}
impl tor_linkspec::HasAddrs for FallbackDir {
fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
self.orports.iter().copied()
}
}
impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
fn ed_identity(&self) -> &Ed25519Identity {
&self.ed_identity
}
fn rsa_identity(&self) -> &RsaIdentity {
&self.rsa_identity
}
}
impl tor_linkspec::DirectChanMethodsHelper for FallbackDir {}
impl tor_linkspec::ChanTarget for FallbackDir {}