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
92impl RelayIdsBuilder {
93 pub fn from_relay_ids<T: HasRelayIds + ?Sized>(ids: &T) -> Self {
99 let mut builder = Self::default();
100 if let Some(ed_id) = ids.ed_identity() {
101 builder.ed_identity(*ed_id);
102 }
103 if let Some(rsa_id) = ids.rsa_identity() {
104 builder.rsa_identity(*rsa_id);
105 }
106 builder
107 }
108}
109
110#[derive(Debug, Clone, derive_builder::Builder)]
113#[builder(derive(Debug))]
114pub struct OwnedChanTarget {
115 #[builder(default)]
117 addrs: Vec<SocketAddr>,
118 #[builder(default = "self.make_method()")]
123 method: ChannelMethod,
124 #[builder(sub_builder)]
126 ids: RelayIds,
127}
128impl_standard_builder! { OwnedChanTarget : !Deserialize + !Builder + !Default }
129
130impl OwnedChanTargetBuilder {
131 pub fn ed_identity(&mut self, id: pk::ed25519::Ed25519Identity) -> &mut Self {
133 self.ids().ed_identity(id);
134 self
135 }
136
137 pub fn rsa_identity(&mut self, id: pk::rsa::RsaIdentity) -> &mut Self {
139 self.ids().rsa_identity(id);
140 self
141 }
142
143 fn make_method(&self) -> ChannelMethod {
145 ChannelMethod::Direct(self.addrs.clone().unwrap_or_default())
146 }
147}
148
149impl HasAddrs for OwnedChanTarget {
150 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
151 self.addrs.iter().copied()
152 }
153}
154
155impl HasChanMethod for OwnedChanTarget {
156 fn chan_method(&self) -> ChannelMethod {
157 self.method.clone()
158 }
159}
160
161impl HasRelayIds for OwnedChanTarget {
162 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
163 self.ids.identity(key_type)
164 }
165}
166
167impl ChanTarget for OwnedChanTarget {}
168
169impl OwnedChanTarget {
170 pub fn from_chan_target<C>(target: &C) -> Self
172 where
173 C: ChanTarget + ?Sized,
174 {
175 OwnedChanTarget {
176 addrs: target.addrs().collect(),
177 method: target.chan_method(),
178 ids: RelayIds::from_relay_ids(target),
179 }
180 }
181
182 pub fn chan_method_mut(&mut self) -> &mut ChannelMethod {
185 &mut self.method
186 }
187}
188
189impl Display for OwnedChanTarget {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 write!(f, "{}", self.display_chan_target())
193 }
194}
195
196impl Redactable for OwnedChanTarget {
197 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 self.display_chan_target().display_redacted(f)
199 }
200
201 fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 self.display_chan_target().debug_redacted(f)
203 }
204}
205
206#[derive(Debug, Clone, derive_builder::Builder)]
209#[builder(derive(Debug))]
210pub struct OwnedCircTarget {
211 #[builder(sub_builder)]
213 chan_target: OwnedChanTarget,
214 ntor_onion_key: pk::curve25519::PublicKey,
216 protocols: tor_protover::Protocols,
218}
219impl_standard_builder! { OwnedCircTarget : !Deserialize + !Builder + !Default }
220
221impl OwnedCircTarget {
222 pub fn from_circ_target<C>(target: &C) -> Self
224 where
225 C: CircTarget + ?Sized,
226 {
227 OwnedCircTarget {
228 chan_target: OwnedChanTarget::from_chan_target(target),
229 ntor_onion_key: *target.ntor_onion_key(),
230 protocols: target.protovers().clone(),
231 }
232 }
233
234 pub fn chan_target_mut(&mut self) -> &mut OwnedChanTarget {
236 &mut self.chan_target
237 }
238
239 pub fn chan_target(&self) -> &OwnedChanTarget {
241 &self.chan_target
242 }
243}
244
245impl HasAddrs for OwnedCircTarget {
246 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
247 self.chan_target.addrs()
248 }
249}
250
251impl HasRelayIds for OwnedCircTarget {
252 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
253 self.chan_target.identity(key_type)
254 }
255}
256impl HasChanMethod for OwnedCircTarget {
257 fn chan_method(&self) -> ChannelMethod {
258 self.chan_target.chan_method()
259 }
260}
261
262impl ChanTarget for OwnedCircTarget {}
263
264impl CircTarget for OwnedCircTarget {
265 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
266 &self.ntor_onion_key
267 }
268 fn protovers(&self) -> &tor_protover::Protocols {
269 &self.protocols
270 }
271}
272
273pub trait IntoOwnedChanTarget {
275 fn to_owned(self) -> OwnedChanTarget;
277
278 fn to_logged(self) -> LoggedChanTarget
280 where
281 Self: Sized,
282 {
283 self.to_owned().into()
284 }
285}
286
287impl<'a, T: ChanTarget + ?Sized> IntoOwnedChanTarget for &'a T {
288 fn to_owned(self) -> OwnedChanTarget {
289 OwnedChanTarget::from_chan_target(self)
290 }
291}
292
293impl IntoOwnedChanTarget for OwnedChanTarget {
294 fn to_owned(self) -> OwnedChanTarget {
295 self
296 }
297}
298
299pub type LoggedChanTarget = safelog::BoxSensitive<OwnedChanTarget>;
301
302#[cfg(test)]
303mod test {
304 #![allow(clippy::bool_assert_comparison)]
306 #![allow(clippy::clone_on_copy)]
307 #![allow(clippy::dbg_macro)]
308 #![allow(clippy::mixed_attributes_style)]
309 #![allow(clippy::print_stderr)]
310 #![allow(clippy::print_stdout)]
311 #![allow(clippy::single_char_pattern)]
312 #![allow(clippy::unwrap_used)]
313 #![allow(clippy::unchecked_time_subtraction)]
314 #![allow(clippy::useless_vec)]
315 #![allow(clippy::needless_pass_by_value)]
316 use super::*;
318 use itertools::Itertools;
319
320 #[test]
321 #[allow(clippy::redundant_clone)]
322 fn chan_target() {
323 let ti = OwnedChanTarget::builder()
324 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
325 .ed_identity([42; 32].into())
326 .rsa_identity([45; 20].into())
327 .build()
328 .unwrap();
329
330 let ti2 = OwnedChanTarget::from_chan_target(&ti);
331 assert_eq!(ti.addrs().collect_vec(), ti2.addrs().collect_vec());
332 assert!(ti.same_relay_ids(&ti2));
333
334 assert_eq!(format!("{:?}", ti), format!("{:?}", ti2));
335 assert_eq!(format!("{:?}", ti), format!("{:?}", ti.clone()));
336 }
337
338 #[test]
339 #[allow(clippy::redundant_clone)]
340 fn circ_target() {
341 let mut builder = OwnedCircTarget::builder();
342 builder
343 .chan_target()
344 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
345 .ed_identity([42; 32].into())
346 .rsa_identity([45; 20].into());
347 let ct = builder
348 .ntor_onion_key([99; 32].into())
349 .protocols("FlowCtrl=7".parse().unwrap())
350 .build()
351 .unwrap();
352 let ch = ct.chan_target.clone();
353
354 assert_eq!(ct.addrs().collect_vec(), ch.addrs().collect_vec());
355 assert!(ct.same_relay_ids(&ch));
356 assert_eq!(ct.ntor_onion_key().as_bytes(), &[99; 32]);
357 assert_eq!(&ct.protovers().to_string(), "FlowCtrl=7");
358 let ct2 = OwnedCircTarget::from_circ_target(&ct);
359 assert_eq!(format!("{:?}", ct), format!("{:?}", ct2));
360 assert_eq!(format!("{:?}", ct), format!("{:?}", ct.clone()));
361 }
362
363 #[test]
364 fn format_relay_ids() {
365 let mut builder = RelayIds::builder();
366 builder
367 .ed_identity([42; 32].into())
368 .rsa_identity([45; 20].into());
369 let ids = builder.build().unwrap();
370 assert_eq!(
371 format!("{}", ids),
372 "ed25519:KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKio $2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"
373 );
374 assert_eq!(format!("{}", ids.redacted()), "ed25519:Ki…");
375 }
376}