use tor_error::{into_internal, HasRetryTime, RetryTime};
use tor_linkspec::{
decode::Strictness, verbatim::VerbatimLinkSpecCircTarget, CircTarget, EncodedLinkSpec,
OwnedChanTargetBuilder, OwnedCircTarget,
};
use tor_llcrypto::pk::curve25519;
use tor_netdir::NetDir;
use tor_netdoc::doc::hsdesc::IntroPointDesc;
fn circtarget_from_pieces(
linkspecs: &[EncodedLinkSpec],
ntor_onion_key: &curve25519::PublicKey,
netdir: &NetDir,
) -> Result<impl CircTarget, InvalidTarget> {
let mut bld = OwnedCircTarget::builder();
let linkspecs_decoded = linkspecs
.iter()
.map(|ls| ls.parse())
.collect::<Result<Vec<_>, _>>()?;
*bld.chan_target() =
OwnedChanTargetBuilder::from_linkspecs(Strictness::Standard, &linkspecs_decoded[..])?;
let protocols = {
let chan_target = bld.chan_target().build().map_err(into_internal!(
"from_linkspecs gave us a non-working ChanTargetBuilder"
))?;
match netdir.by_ids_detailed(&chan_target)? {
Some(relay) => relay.protovers().clone(),
None => netdir.relay_protocol_status().required_protocols().clone(),
}
};
bld.protocols(protocols);
bld.ntor_onion_key(*ntor_onion_key);
let circ_target = bld.build().map_err(into_internal!(
"somehow we made an invalid CircTargetBuilder"
))?;
Ok(VerbatimLinkSpecCircTarget::new(
circ_target,
linkspecs.to_vec(),
))
}
pub(crate) fn ipt_to_circtarget(
desc: &IntroPointDesc,
netdir: &NetDir,
) -> Result<impl CircTarget, InvalidTarget> {
circtarget_from_pieces(desc.link_specifiers(), desc.ipt_ntor_key(), netdir)
}
#[derive(Clone, Debug, thiserror::Error)]
#[non_exhaustive]
pub enum InvalidTarget {
#[error("Misformed channel target information provided")]
UnparseableChanTargetInfo(#[from] tor_bytes::Error),
#[error("Invalid channel target information provided")]
InvalidChanTargetInfo(#[from] tor_linkspec::decode::ChanTargetDecodeError),
#[error("Impossible combination of relay identities")]
ImpossibleRelayIds(#[from] tor_netdir::RelayLookupError),
#[error("{0}")]
Bug(#[from] tor_error::Bug),
}
impl HasRetryTime for InvalidTarget {
fn retry_time(&self) -> RetryTime {
use InvalidTarget as IT;
use RetryTime as RT;
match self {
IT::UnparseableChanTargetInfo(..) => RT::Never,
IT::InvalidChanTargetInfo(..) => RT::Never,
IT::ImpossibleRelayIds(..) => RT::Never,
IT::Bug(..) => RT::Never,
}
}
}