1use safelog::Redactable;
4use serde::{Deserialize, Serialize};
5use std::fmt::{self, Display};
6use std::net::SocketAddr;
7use tor_config::impl_standard_builder;
8use tor_llcrypto::pk;
9
10use crate::{
11 ChanTarget, ChannelMethod, CircTarget, HasAddrs, HasChanMethod, HasRelayIds, RelayIdRef,
12 RelayIdType,
13};
14
15#[derive(
21 Debug,
22 Clone,
23 Eq,
24 PartialEq,
25 Hash,
26 PartialOrd,
27 Ord,
28 Serialize,
29 Deserialize,
30 derive_builder::Builder,
31)]
32#[builder(derive(Debug))]
33pub struct RelayIds {
34 #[serde(rename = "ed25519")]
36 #[builder(default, setter(strip_option))]
37 ed_identity: Option<pk::ed25519::Ed25519Identity>,
38 #[serde(rename = "rsa")]
40 #[builder(default, setter(strip_option))]
41 rsa_identity: Option<pk::rsa::RsaIdentity>,
42}
43impl_standard_builder! { RelayIds : !Deserialize + !Builder + !Default }
44
45impl HasRelayIds for RelayIds {
46 fn identity(&self, key_type: RelayIdType) -> Option<crate::RelayIdRef<'_>> {
47 match key_type {
48 RelayIdType::Ed25519 => self.ed_identity.as_ref().map(RelayIdRef::from),
49 RelayIdType::Rsa => self.rsa_identity.as_ref().map(RelayIdRef::from),
50 }
51 }
52}
53
54impl RelayIds {
55 pub const fn empty() -> Self {
60 Self {
61 ed_identity: None,
62 rsa_identity: None,
63 }
64 }
65
66 pub fn from_relay_ids<T: HasRelayIds + ?Sized>(other: &T) -> Self {
72 Self {
73 ed_identity: other
74 .identity(RelayIdType::Ed25519)
75 .map(|r| *r.unwrap_ed25519()),
76 rsa_identity: other.identity(RelayIdType::Rsa).map(|r| *r.unwrap_rsa()),
77 }
78 }
79}
80
81impl std::fmt::Display for RelayIds {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{}", self.display_relay_ids())
84 }
85}
86impl Redactable for RelayIds {
87 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 write!(f, "{}", self.display_relay_ids().redacted())
89 }
90}
91
92#[derive(Debug, Clone, derive_builder::Builder)]
95#[builder(derive(Debug))]
96pub struct OwnedChanTarget {
97 #[builder(default)]
99 addrs: Vec<SocketAddr>,
100 #[builder(default = "self.make_method()")]
105 method: ChannelMethod,
106 #[builder(sub_builder)]
108 ids: RelayIds,
109}
110impl_standard_builder! { OwnedChanTarget : !Deserialize + !Builder + !Default }
111
112impl OwnedChanTargetBuilder {
113 pub fn ed_identity(&mut self, id: pk::ed25519::Ed25519Identity) -> &mut Self {
115 self.ids().ed_identity(id);
116 self
117 }
118
119 pub fn rsa_identity(&mut self, id: pk::rsa::RsaIdentity) -> &mut Self {
121 self.ids().rsa_identity(id);
122 self
123 }
124
125 fn make_method(&self) -> ChannelMethod {
127 ChannelMethod::Direct(self.addrs.clone().unwrap_or_default())
128 }
129}
130
131impl HasAddrs for OwnedChanTarget {
132 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
133 self.addrs.iter().copied()
134 }
135}
136
137impl HasChanMethod for OwnedChanTarget {
138 fn chan_method(&self) -> ChannelMethod {
139 self.method.clone()
140 }
141}
142
143impl HasRelayIds for OwnedChanTarget {
144 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
145 self.ids.identity(key_type)
146 }
147}
148
149impl ChanTarget for OwnedChanTarget {}
150
151impl OwnedChanTarget {
152 pub fn from_chan_target<C>(target: &C) -> Self
154 where
155 C: ChanTarget + ?Sized,
156 {
157 OwnedChanTarget {
158 addrs: target.addrs().collect(),
159 method: target.chan_method(),
160 ids: RelayIds::from_relay_ids(target),
161 }
162 }
163
164 pub fn chan_method_mut(&mut self) -> &mut ChannelMethod {
167 &mut self.method
168 }
169}
170
171impl Display for OwnedChanTarget {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 write!(f, "{}", self.display_chan_target())
175 }
176}
177
178impl Redactable for OwnedChanTarget {
179 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 self.display_chan_target().display_redacted(f)
181 }
182
183 fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 self.display_chan_target().debug_redacted(f)
185 }
186}
187
188#[derive(Debug, Clone, derive_builder::Builder)]
191#[builder(derive(Debug))]
192pub struct OwnedCircTarget {
193 #[builder(sub_builder)]
195 chan_target: OwnedChanTarget,
196 ntor_onion_key: pk::curve25519::PublicKey,
198 protocols: tor_protover::Protocols,
200}
201impl_standard_builder! { OwnedCircTarget : !Deserialize + !Builder + !Default }
202
203impl OwnedCircTarget {
204 pub fn from_circ_target<C>(target: &C) -> Self
206 where
207 C: CircTarget + ?Sized,
208 {
209 OwnedCircTarget {
210 chan_target: OwnedChanTarget::from_chan_target(target),
211 ntor_onion_key: *target.ntor_onion_key(),
212 protocols: target.protovers().clone(),
213 }
214 }
215
216 pub fn chan_target_mut(&mut self) -> &mut OwnedChanTarget {
218 &mut self.chan_target
219 }
220
221 pub fn chan_target(&self) -> &OwnedChanTarget {
223 &self.chan_target
224 }
225}
226
227impl HasAddrs for OwnedCircTarget {
228 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
229 self.chan_target.addrs()
230 }
231}
232
233impl HasRelayIds for OwnedCircTarget {
234 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
235 self.chan_target.identity(key_type)
236 }
237}
238impl HasChanMethod for OwnedCircTarget {
239 fn chan_method(&self) -> ChannelMethod {
240 self.chan_target.chan_method()
241 }
242}
243
244impl ChanTarget for OwnedCircTarget {}
245
246impl CircTarget for OwnedCircTarget {
247 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
248 &self.ntor_onion_key
249 }
250 fn protovers(&self) -> &tor_protover::Protocols {
251 &self.protocols
252 }
253}
254
255pub trait IntoOwnedChanTarget {
257 fn to_owned(self) -> OwnedChanTarget;
259
260 fn to_logged(self) -> LoggedChanTarget
262 where
263 Self: Sized,
264 {
265 self.to_owned().into()
266 }
267}
268
269impl<'a, T: ChanTarget + ?Sized> IntoOwnedChanTarget for &'a T {
270 fn to_owned(self) -> OwnedChanTarget {
271 OwnedChanTarget::from_chan_target(self)
272 }
273}
274
275impl IntoOwnedChanTarget for OwnedChanTarget {
276 fn to_owned(self) -> OwnedChanTarget {
277 self
278 }
279}
280
281pub type LoggedChanTarget = safelog::BoxSensitive<OwnedChanTarget>;
283
284#[cfg(test)]
285mod test {
286 #![allow(clippy::bool_assert_comparison)]
288 #![allow(clippy::clone_on_copy)]
289 #![allow(clippy::dbg_macro)]
290 #![allow(clippy::mixed_attributes_style)]
291 #![allow(clippy::print_stderr)]
292 #![allow(clippy::print_stdout)]
293 #![allow(clippy::single_char_pattern)]
294 #![allow(clippy::unwrap_used)]
295 #![allow(clippy::unchecked_time_subtraction)]
296 #![allow(clippy::useless_vec)]
297 #![allow(clippy::needless_pass_by_value)]
298 use super::*;
300 use itertools::Itertools;
301
302 #[test]
303 #[allow(clippy::redundant_clone)]
304 fn chan_target() {
305 let ti = OwnedChanTarget::builder()
306 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
307 .ed_identity([42; 32].into())
308 .rsa_identity([45; 20].into())
309 .build()
310 .unwrap();
311
312 let ti2 = OwnedChanTarget::from_chan_target(&ti);
313 assert_eq!(ti.addrs().collect_vec(), ti2.addrs().collect_vec());
314 assert!(ti.same_relay_ids(&ti2));
315
316 assert_eq!(format!("{:?}", ti), format!("{:?}", ti2));
317 assert_eq!(format!("{:?}", ti), format!("{:?}", ti.clone()));
318 }
319
320 #[test]
321 #[allow(clippy::redundant_clone)]
322 fn circ_target() {
323 let mut builder = OwnedCircTarget::builder();
324 builder
325 .chan_target()
326 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
327 .ed_identity([42; 32].into())
328 .rsa_identity([45; 20].into());
329 let ct = builder
330 .ntor_onion_key([99; 32].into())
331 .protocols("FlowCtrl=7".parse().unwrap())
332 .build()
333 .unwrap();
334 let ch = ct.chan_target.clone();
335
336 assert_eq!(ct.addrs().collect_vec(), ch.addrs().collect_vec());
337 assert!(ct.same_relay_ids(&ch));
338 assert_eq!(ct.ntor_onion_key().as_bytes(), &[99; 32]);
339 assert_eq!(&ct.protovers().to_string(), "FlowCtrl=7");
340 let ct2 = OwnedCircTarget::from_circ_target(&ct);
341 assert_eq!(format!("{:?}", ct), format!("{:?}", ct2));
342 assert_eq!(format!("{:?}", ct), format!("{:?}", ct.clone()));
343 }
344
345 #[test]
346 fn format_relay_ids() {
347 let mut builder = RelayIds::builder();
348 builder
349 .ed_identity([42; 32].into())
350 .rsa_identity([45; 20].into());
351 let ids = builder.build().unwrap();
352 assert_eq!(
353 format!("{}", ids),
354 "ed25519:KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKio $2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"
355 );
356 assert_eq!(format!("{}", ids.redacted()), "ed25519:Ki…");
357 }
358}