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", default)]
39 #[builder(default, setter(strip_option))]
40 ed_identity: Option<pk::ed25519::Ed25519Identity>,
41
42 #[serde(rename = "rsa", default)]
44 #[builder(default, setter(strip_option))]
45 rsa_identity: Option<pk::rsa::RsaIdentity>,
46}
47impl_standard_builder! { RelayIds : !Deserialize + !Builder + !Default }
48
49impl HasRelayIds for RelayIds {
50 fn identity(&self, key_type: RelayIdType) -> Option<crate::RelayIdRef<'_>> {
51 match key_type {
52 RelayIdType::Ed25519 => self.ed_identity.as_ref().map(RelayIdRef::from),
53 RelayIdType::Rsa => self.rsa_identity.as_ref().map(RelayIdRef::from),
54 }
55 }
56}
57
58impl RelayIds {
59 pub const fn empty() -> Self {
64 Self {
65 ed_identity: None,
66 rsa_identity: None,
67 }
68 }
69
70 pub fn from_relay_ids<T: HasRelayIds + ?Sized>(other: &T) -> Self {
76 Self {
77 ed_identity: other
78 .identity(RelayIdType::Ed25519)
79 .map(|r| *r.unwrap_ed25519()),
80 rsa_identity: other.identity(RelayIdType::Rsa).map(|r| *r.unwrap_rsa()),
81 }
82 }
83}
84
85impl std::fmt::Display for RelayIds {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "{}", self.display_relay_ids())
88 }
89}
90impl Redactable for RelayIds {
91 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 write!(f, "{}", self.display_relay_ids().redacted())
93 }
94}
95
96impl RelayIdsBuilder {
97 pub fn from_relay_ids<T: HasRelayIds + ?Sized>(ids: &T) -> Self {
103 let mut builder = Self::default();
104 if let Some(ed_id) = ids.ed_identity() {
105 builder.ed_identity(*ed_id);
106 }
107 if let Some(rsa_id) = ids.rsa_identity() {
108 builder.rsa_identity(*rsa_id);
109 }
110 builder
111 }
112}
113
114#[derive(Debug, Clone, derive_builder::Builder)]
117#[builder(derive(Debug))]
118pub struct OwnedChanTarget {
119 #[builder(default)]
121 addrs: Vec<SocketAddr>,
122 #[builder(default = "self.make_method()")]
127 method: ChannelMethod,
128 #[builder(sub_builder)]
130 ids: RelayIds,
131}
132impl_standard_builder! { OwnedChanTarget : !Deserialize + !Builder + !Default }
133
134impl OwnedChanTargetBuilder {
135 pub fn ed_identity(&mut self, id: pk::ed25519::Ed25519Identity) -> &mut Self {
137 self.ids().ed_identity(id);
138 self
139 }
140
141 pub fn rsa_identity(&mut self, id: pk::rsa::RsaIdentity) -> &mut Self {
143 self.ids().rsa_identity(id);
144 self
145 }
146
147 fn make_method(&self) -> ChannelMethod {
149 ChannelMethod::Direct(self.addrs.clone().unwrap_or_default())
150 }
151}
152
153impl HasAddrs for OwnedChanTarget {
154 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
155 self.addrs.iter().copied()
156 }
157}
158
159impl HasChanMethod for OwnedChanTarget {
160 fn chan_method(&self) -> ChannelMethod {
161 self.method.clone()
162 }
163}
164
165impl HasRelayIds for OwnedChanTarget {
166 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
167 self.ids.identity(key_type)
168 }
169}
170
171impl ChanTarget for OwnedChanTarget {}
172
173impl OwnedChanTarget {
174 pub fn from_chan_target<C>(target: &C) -> Self
176 where
177 C: ChanTarget + ?Sized,
178 {
179 OwnedChanTarget {
180 addrs: target.addrs().collect(),
181 method: target.chan_method(),
182 ids: RelayIds::from_relay_ids(target),
183 }
184 }
185
186 pub fn chan_method_mut(&mut self) -> &mut ChannelMethod {
189 &mut self.method
190 }
191}
192
193impl Display for OwnedChanTarget {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 write!(f, "{}", self.display_chan_target())
197 }
198}
199
200impl Redactable for OwnedChanTarget {
201 fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 self.display_chan_target().display_redacted(f)
203 }
204
205 fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206 self.display_chan_target().debug_redacted(f)
207 }
208}
209
210#[derive(Debug, Clone, derive_builder::Builder)]
213#[builder(derive(Debug))]
214pub struct OwnedCircTarget {
215 #[builder(sub_builder)]
217 chan_target: OwnedChanTarget,
218 ntor_onion_key: pk::curve25519::PublicKey,
220 protocols: tor_protover::Protocols,
222}
223impl_standard_builder! { OwnedCircTarget : !Deserialize + !Builder + !Default }
224
225impl OwnedCircTarget {
226 pub fn from_circ_target<C>(target: &C) -> Self
228 where
229 C: CircTarget + ?Sized,
230 {
231 OwnedCircTarget {
232 chan_target: OwnedChanTarget::from_chan_target(target),
233 ntor_onion_key: *target.ntor_onion_key(),
234 protocols: target.protovers().clone(),
235 }
236 }
237
238 pub fn chan_target_mut(&mut self) -> &mut OwnedChanTarget {
240 &mut self.chan_target
241 }
242
243 pub fn chan_target(&self) -> &OwnedChanTarget {
245 &self.chan_target
246 }
247}
248
249impl HasAddrs for OwnedCircTarget {
250 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
251 self.chan_target.addrs()
252 }
253}
254
255impl HasRelayIds for OwnedCircTarget {
256 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
257 self.chan_target.identity(key_type)
258 }
259}
260impl HasChanMethod for OwnedCircTarget {
261 fn chan_method(&self) -> ChannelMethod {
262 self.chan_target.chan_method()
263 }
264}
265
266impl ChanTarget for OwnedCircTarget {}
267
268impl CircTarget for OwnedCircTarget {
269 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
270 &self.ntor_onion_key
271 }
272 fn protovers(&self) -> &tor_protover::Protocols {
273 &self.protocols
274 }
275}
276
277pub trait IntoOwnedChanTarget {
279 fn to_owned(self) -> OwnedChanTarget;
281
282 fn to_logged(self) -> LoggedChanTarget
284 where
285 Self: Sized,
286 {
287 self.to_owned().into()
288 }
289}
290
291impl<'a, T: ChanTarget + ?Sized> IntoOwnedChanTarget for &'a T {
292 fn to_owned(self) -> OwnedChanTarget {
293 OwnedChanTarget::from_chan_target(self)
294 }
295}
296
297impl IntoOwnedChanTarget for OwnedChanTarget {
298 fn to_owned(self) -> OwnedChanTarget {
299 self
300 }
301}
302
303pub type LoggedChanTarget = safelog::BoxSensitive<OwnedChanTarget>;
305
306#[cfg(test)]
307mod test {
308 #![allow(clippy::bool_assert_comparison)]
310 #![allow(clippy::clone_on_copy)]
311 #![allow(clippy::dbg_macro)]
312 #![allow(clippy::mixed_attributes_style)]
313 #![allow(clippy::print_stderr)]
314 #![allow(clippy::print_stdout)]
315 #![allow(clippy::single_char_pattern)]
316 #![allow(clippy::unwrap_used)]
317 #![allow(clippy::unchecked_time_subtraction)]
318 #![allow(clippy::useless_vec)]
319 #![allow(clippy::needless_pass_by_value)]
320 use super::*;
322 use itertools::Itertools;
323
324 #[test]
325 #[allow(clippy::redundant_clone)]
326 fn chan_target() {
327 let ti = OwnedChanTarget::builder()
328 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
329 .ed_identity([42; 32].into())
330 .rsa_identity([45; 20].into())
331 .build()
332 .unwrap();
333
334 let ti2 = OwnedChanTarget::from_chan_target(&ti);
335 assert_eq!(ti.addrs().collect_vec(), ti2.addrs().collect_vec());
336 assert!(ti.same_relay_ids(&ti2));
337
338 assert_eq!(format!("{:?}", ti), format!("{:?}", ti2));
339 assert_eq!(format!("{:?}", ti), format!("{:?}", ti.clone()));
340 }
341
342 #[test]
343 #[allow(clippy::redundant_clone)]
344 fn circ_target() {
345 let mut builder = OwnedCircTarget::builder();
346 builder
347 .chan_target()
348 .addrs(vec!["127.0.0.1:11".parse().unwrap()])
349 .ed_identity([42; 32].into())
350 .rsa_identity([45; 20].into());
351 let ct = builder
352 .ntor_onion_key([99; 32].into())
353 .protocols("FlowCtrl=7".parse().unwrap())
354 .build()
355 .unwrap();
356 let ch = ct.chan_target.clone();
357
358 assert_eq!(ct.addrs().collect_vec(), ch.addrs().collect_vec());
359 assert!(ct.same_relay_ids(&ch));
360 assert_eq!(ct.ntor_onion_key().as_bytes(), &[99; 32]);
361 assert_eq!(&ct.protovers().to_string(), "FlowCtrl=7");
362 let ct2 = OwnedCircTarget::from_circ_target(&ct);
363 assert_eq!(format!("{:?}", ct), format!("{:?}", ct2));
364 assert_eq!(format!("{:?}", ct), format!("{:?}", ct.clone()));
365 }
366
367 #[test]
368 fn format_relay_ids() {
369 let mut builder = RelayIds::builder();
370 builder
371 .ed_identity([42; 32].into())
372 .rsa_identity([45; 20].into());
373 let ids = builder.build().unwrap();
374 assert_eq!(
375 format!("{}", ids),
376 "ed25519:KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKio $2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"
377 );
378 assert_eq!(format!("{}", ids.redacted()), "ed25519:Ki…");
379 }
380}