//! Wrappers for using a CircTarget with a verbatim list of //! [link specifiers](EncodedLinkSpec). use crate::{ChanTarget, CircTarget, EncodedLinkSpec, HasAddrs, HasChanMethod, HasRelayIds}; /// A wrapper around an underlying [`CircTarget`] that provides a user-specified /// list of [link specifiers](EncodedLinkSpec). /// /// Onion services and their clients use this type of target when telling a /// relay to extend a circuit to a target relay (an introduction point or /// rendezvous point) chosen by some other party. #[derive(Clone, Debug)] pub struct VerbatimLinkSpecCircTarget { /// The underlying CircTarget target: T, /// The link specifiers to provide. linkspecs: Vec, } impl VerbatimLinkSpecCircTarget { /// Construct a new `VerbatimLinkSpecCircTarget` to wrap an underlying /// `CircTarget` object, and provide it with a new set of encoded link /// specifiers that will be used when telling a relay to extend to this /// node. /// /// Note that nothing here will check that `linkspecs` is sufficient to /// actually connect to the chosen target, or to any target at all. It is /// the caller's responsibility to choose a valid set of link specifiers. pub fn new(target: T, linkspecs: Vec) -> Self { Self { target, linkspecs } } } // Now, the delegation functions. All of these are simple delegations to // self.target, except for `CircTarget::linkspecs` with returns self.linkspecs. impl HasRelayIds for VerbatimLinkSpecCircTarget { fn identity(&self, key_type: crate::RelayIdType) -> Option> { self.target.identity(key_type) } } impl HasAddrs for VerbatimLinkSpecCircTarget { fn addrs(&self) -> impl Iterator { self.target.addrs() } } impl HasChanMethod for VerbatimLinkSpecCircTarget { fn chan_method(&self) -> crate::ChannelMethod { self.target.chan_method() } } impl ChanTarget for VerbatimLinkSpecCircTarget {} impl CircTarget for VerbatimLinkSpecCircTarget { fn linkspecs(&self) -> tor_bytes::EncodeResult> { Ok(self.linkspecs.clone()) } fn ntor_onion_key(&self) -> &tor_llcrypto::pk::curve25519::PublicKey { self.target.ntor_onion_key() } fn protovers(&self) -> &tor_protover::Protocols { self.target.protovers() } } #[cfg(test)] mod test { // @@ begin test lint list maintained by maint/add_warning @@ #![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)] #![allow(clippy::string_slice)] // See arti#2571 //! use super::*; use crate::OwnedCircTarget; use itertools::Itertools; #[test] fn verbatim_linkspecs() { let mut builder = OwnedCircTarget::builder(); builder .chan_target() .addrs(vec!["127.0.0.1:11".parse().unwrap()]) .ed_identity([42; 32].into()) .rsa_identity([45; 20].into()); let inner = builder .ntor_onion_key([99; 32].into()) .protocols("FlowCtrl=7".parse().unwrap()) .build() .unwrap(); let weird_linkspecs = vec![EncodedLinkSpec::new( 77.into(), b"mysterious whisper".to_vec(), )]; let wrapped = VerbatimLinkSpecCircTarget::new(inner.clone(), weird_linkspecs.clone()); assert_eq!(wrapped.addrs().collect_vec(), inner.addrs().collect_vec()); assert!(wrapped.same_relay_ids(&inner)); assert_eq!(wrapped.ntor_onion_key(), inner.ntor_onion_key()); assert_eq!(wrapped.protovers(), inner.protovers()); assert_ne!(inner.linkspecs().unwrap(), weird_linkspecs); assert_eq!(wrapped.linkspecs().unwrap(), weird_linkspecs); } }