1use derive_deftly::derive_deftly_adhoc;
5use safelog::Redactable;
6use std::{fmt, iter::FusedIterator, net::SocketAddr};
7use tor_llcrypto::pk;
8
9use crate::{ChannelMethod, RelayIdRef, RelayIdType, RelayIdTypeIter};
10
11#[cfg(feature = "pt-client")]
12use crate::PtTargetAddr;
13
14pub trait HasRelayIdsLegacy {
19 fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity;
21 fn rsa_identity(&self) -> &pk::rsa::RsaIdentity;
23}
24
25pub trait HasRelayIds {
31 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>>;
37
38 fn identities(&self) -> RelayIdIter<'_, Self> {
40 RelayIdIter {
41 info: self,
42 next_key: RelayIdType::all_types(),
43 }
44 }
45
46 fn ed_identity(&self) -> Option<&pk::ed25519::Ed25519Identity> {
48 self.identity(RelayIdType::Ed25519)
49 .map(RelayIdRef::unwrap_ed25519)
50 }
51
52 fn rsa_identity(&self) -> Option<&pk::rsa::RsaIdentity> {
54 self.identity(RelayIdType::Rsa).map(RelayIdRef::unwrap_rsa)
55 }
56
57 fn has_identity(&self, id: RelayIdRef<'_>) -> bool {
66 self.identity(id.id_type()).map(|my_id| my_id == id) == Some(true)
67 }
68
69 fn has_any_identity(&self) -> bool {
71 RelayIdType::all_types().any(|id_type| self.identity(id_type).is_some())
72 }
73
74 #[allow(clippy::nonminimal_bool)] fn same_relay_ids<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
86 derive_deftly_adhoc! {
117 RelayIdType:
118 $(
119 self.identity($vtype) == other.identity($vtype) &&
120 )
121 true
122 }
123 }
124
125 fn has_all_relay_ids_from<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
130 RelayIdType::all_types().all(|key_type| {
131 match (self.identity(key_type), other.identity(key_type)) {
132 (Some(mine), Some(theirs)) if mine == theirs => true,
134 (_, Some(_theirs)) => false,
136 (_, None) => true,
138 }
139 })
140 }
141
142 fn has_any_relay_id_from<T: HasRelayIds + ?Sized>(&self, other: &T) -> bool {
147 RelayIdType::all_types()
148 .filter_map(|key_type| Some((self.identity(key_type)?, other.identity(key_type)?)))
149 .any(|(self_id, other_id)| self_id == other_id)
150 }
151
152 fn cmp_by_relay_ids<T: HasRelayIds + ?Sized>(&self, other: &T) -> std::cmp::Ordering {
161 for key_type in RelayIdType::all_types() {
162 let ordering = Ord::cmp(&self.identity(key_type), &other.identity(key_type));
163 if ordering.is_ne() {
164 return ordering;
165 }
166 }
167 std::cmp::Ordering::Equal
168 }
169
170 fn display_relay_ids(&self) -> DisplayRelayIds<'_, Self> {
173 DisplayRelayIds { inner: self }
174 }
175}
176
177impl<T: HasRelayIdsLegacy> HasRelayIds for T {
178 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
179 match key_type {
180 RelayIdType::Rsa => Some(self.rsa_identity().into()),
181 RelayIdType::Ed25519 => Some(self.ed_identity().into()),
182 }
183 }
184}
185
186#[derive(Clone)]
189pub struct DisplayRelayIds<'a, T: HasRelayIds + ?Sized> {
190 inner: &'a T,
192}
193impl<'a, T: HasRelayIds + ?Sized> fmt::Debug for DisplayRelayIds<'a, T> {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 f.debug_struct("DisplayRelayIds").finish_non_exhaustive()
197 }
198}
199
200impl<'a, T: HasRelayIds + ?Sized> DisplayRelayIds<'a, T> {
201 fn fmt_impl(&self, f: &mut fmt::Formatter<'_>, redact: bool) -> fmt::Result {
203 let mut iter = self.inner.identities();
204 if let Some(ident) = iter.next() {
205 write!(f, "{}", ident.maybe_redacted(redact))?;
206 }
207 if redact {
208 return Ok(());
209 }
210 for ident in iter {
211 write!(f, " {}", ident.maybe_redacted(redact))?;
212 }
213 Ok(())
214 }
215}
216impl<'a, T: HasRelayIds + ?Sized> fmt::Display for DisplayRelayIds<'a, T> {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 self.fmt_impl(f, false)
219 }
220}
221impl<'a, T: HasRelayIds + ?Sized> Redactable for DisplayRelayIds<'a, T> {
222 fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 self.fmt_impl(f, true)
224 }
225}
226
227#[derive(Clone)]
229pub struct RelayIdIter<'a, T: HasRelayIds + ?Sized> {
230 info: &'a T,
232 next_key: RelayIdTypeIter,
234}
235
236impl<'a, T: HasRelayIds + ?Sized> Iterator for RelayIdIter<'a, T> {
237 type Item = RelayIdRef<'a>;
238
239 fn next(&mut self) -> Option<Self::Item> {
240 for key_type in &mut self.next_key {
241 if let Some(key) = self.info.identity(key_type) {
242 return Some(key);
243 }
244 }
245 None
246 }
247}
248impl<'a, T: HasRelayIds + ?Sized> FusedIterator for RelayIdIter<'a, T> {}
250
251pub trait HasAddrs {
253 fn addrs(&self) -> &[SocketAddr];
269}
270
271impl<T: HasAddrs> HasAddrs for &T {
272 fn addrs(&self) -> &[SocketAddr] {
273 <T as HasAddrs>::addrs(self)
275 }
276}
277
278pub trait HasChanMethod {
280 fn chan_method(&self) -> ChannelMethod;
285}
286
287pub trait DirectChanMethodsHelper: HasAddrs {}
291
292impl<D: DirectChanMethodsHelper> HasChanMethod for D {
293 fn chan_method(&self) -> ChannelMethod {
294 ChannelMethod::Direct(self.addrs().to_vec())
295 }
296}
297
298pub trait ChanTarget: HasRelayIds + HasAddrs + HasChanMethod {
304 fn display_chan_target(&self) -> DisplayChanTarget<'_, Self>
310 where
311 Self: Sized,
312 {
313 DisplayChanTarget { inner: self }
314 }
315}
316
317pub trait CircTarget: ChanTarget {
322 fn linkspecs(&self) -> tor_bytes::EncodeResult<Vec<crate::EncodedLinkSpec>> {
337 let mut result: Vec<_> = self.identities().map(|id| id.to_owned().into()).collect();
338 #[allow(irrefutable_let_patterns)]
339 if let ChannelMethod::Direct(addrs) = self.chan_method() {
340 result.extend(addrs.into_iter().map(crate::LinkSpec::from));
341 }
342 crate::LinkSpec::sort_by_type(&mut result[..]);
343 result.into_iter().map(|ls| ls.encode()).collect()
344 }
345 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey;
347 fn protovers(&self) -> &tor_protover::Protocols;
349}
350
351#[derive(Debug, Clone)]
354pub struct DisplayChanTarget<'a, T> {
355 inner: &'a T,
357}
358
359impl<'a, T: ChanTarget> DisplayChanTarget<'a, T> {
360 fn fmt_impl(&self, f: &mut fmt::Formatter<'_>, redact: bool) -> fmt::Result {
362 write!(f, "[")?;
363 match self.inner.chan_method() {
367 ChannelMethod::Direct(v) if v.is_empty() => write!(f, "?")?,
368 ChannelMethod::Direct(v) if v.len() == 1 => {
369 write!(f, "{}", v[0].maybe_redacted(redact))?;
370 }
371 ChannelMethod::Direct(v) => write!(f, "{}+", v[0].maybe_redacted(redact))?,
372 #[cfg(feature = "pt-client")]
373 ChannelMethod::Pluggable(target) => {
374 match target.addr() {
375 PtTargetAddr::None => {}
376 other => write!(f, "{} ", other.maybe_redacted(redact))?,
377 }
378 write!(f, "via {}", target.transport())?;
379 }
382 }
383
384 write!(f, " ")?;
385 self.inner.display_relay_ids().fmt_impl(f, redact)?;
386
387 write!(f, "]")
388 }
389}
390
391impl<'a, T: ChanTarget> fmt::Display for DisplayChanTarget<'a, T> {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 self.fmt_impl(f, false)
394 }
395}
396
397impl<'a, T: ChanTarget + fmt::Debug> safelog::Redactable for DisplayChanTarget<'a, T> {
398 fn display_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399 self.fmt_impl(f, true)
400 }
401 fn debug_redacted(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 write!(f, "ChanTarget({:?})", self.redacted().to_string())
403 }
404}
405
406#[cfg(test)]
407mod test {
408 #![allow(clippy::bool_assert_comparison)]
410 #![allow(clippy::clone_on_copy)]
411 #![allow(clippy::dbg_macro)]
412 #![allow(clippy::mixed_attributes_style)]
413 #![allow(clippy::print_stderr)]
414 #![allow(clippy::print_stdout)]
415 #![allow(clippy::single_char_pattern)]
416 #![allow(clippy::unwrap_used)]
417 #![allow(clippy::unchecked_duration_subtraction)]
418 #![allow(clippy::useless_vec)]
419 #![allow(clippy::needless_pass_by_value)]
420 use super::*;
422 use crate::RelayIds;
423 use hex_literal::hex;
424 use std::net::IpAddr;
425 use tor_llcrypto::pk::{self, ed25519::Ed25519Identity, rsa::RsaIdentity};
426
427 struct Example {
428 addrs: Vec<SocketAddr>,
429 ed_id: pk::ed25519::Ed25519Identity,
430 rsa_id: pk::rsa::RsaIdentity,
431 ntor: pk::curve25519::PublicKey,
432 pv: tor_protover::Protocols,
433 }
434 impl HasAddrs for Example {
435 fn addrs(&self) -> &[SocketAddr] {
436 &self.addrs[..]
437 }
438 }
439 impl DirectChanMethodsHelper for Example {}
440 impl HasRelayIdsLegacy for Example {
441 fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
442 &self.ed_id
443 }
444 fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
445 &self.rsa_id
446 }
447 }
448 impl ChanTarget for Example {}
449 impl CircTarget for Example {
450 fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
451 &self.ntor
452 }
453 fn protovers(&self) -> &tor_protover::Protocols {
454 &self.pv
455 }
456 }
457
458 fn example() -> Example {
460 Example {
461 addrs: vec![
462 "127.0.0.1:99".parse::<SocketAddr>().unwrap(),
463 "[::1]:909".parse::<SocketAddr>().unwrap(),
464 ],
465 ed_id: pk::ed25519::PublicKey::from_bytes(&hex!(
466 "fc51cd8e6218a1a38da47ed00230f058
467 0816ed13ba3303ac5deb911548908025"
468 ))
469 .unwrap()
470 .into(),
471 rsa_id: pk::rsa::RsaIdentity::from_bytes(&hex!(
472 "1234567890abcdef12341234567890abcdef1234"
473 ))
474 .unwrap(),
475 ntor: pk::curve25519::PublicKey::from(hex!(
476 "e6db6867583030db3594c1a424b15f7c
477 726624ec26b3353b10a903a6d0ab1c4c"
478 )),
479 pv: tor_protover::Protocols::default(),
480 }
481 }
482
483 #[test]
484 fn test_linkspecs() {
485 let ex = example();
486 let specs = ex
487 .linkspecs()
488 .unwrap()
489 .into_iter()
490 .map(|ls| ls.parse())
491 .collect::<Result<Vec<_>, _>>()
492 .unwrap();
493 assert_eq!(4, specs.len());
494
495 use crate::ls::LinkSpec;
496 assert_eq!(
497 specs[0],
498 LinkSpec::OrPort("127.0.0.1".parse::<IpAddr>().unwrap(), 99)
499 );
500 assert_eq!(
501 specs[1],
502 LinkSpec::RsaId(
503 pk::rsa::RsaIdentity::from_bytes(&hex!("1234567890abcdef12341234567890abcdef1234"))
504 .unwrap()
505 )
506 );
507 assert_eq!(
508 specs[2],
509 LinkSpec::Ed25519Id(
510 pk::ed25519::PublicKey::from_bytes(&hex!(
511 "fc51cd8e6218a1a38da47ed00230f058
512 0816ed13ba3303ac5deb911548908025"
513 ))
514 .unwrap()
515 .into()
516 )
517 );
518 assert_eq!(
519 specs[3],
520 LinkSpec::OrPort("::1".parse::<IpAddr>().unwrap(), 909)
521 );
522 }
523
524 #[test]
525 fn cmp_by_ids() {
526 use crate::RelayIds;
527 use std::cmp::Ordering;
528 fn b(ed: Option<Ed25519Identity>, rsa: Option<RsaIdentity>) -> RelayIds {
529 let mut b = RelayIds::builder();
530 if let Some(ed) = ed {
531 b.ed_identity(ed);
532 }
533 if let Some(rsa) = rsa {
534 b.rsa_identity(rsa);
535 }
536 b.build().unwrap()
537 }
538 fn assert_sorted(v: &[RelayIds]) {
540 for slice in v.windows(2) {
541 assert_eq!(slice[0].cmp_by_relay_ids(&slice[1]), Ordering::Less);
542 assert_eq!(slice[1].cmp_by_relay_ids(&slice[0]), Ordering::Greater);
543 assert_eq!(slice[0].cmp_by_relay_ids(&slice[0]), Ordering::Equal);
544 }
545 }
546
547 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
548 let ed2 = hex!("6962696c69747920746f20656e666f72636520616c6c20746865206c6177730a").into();
549 let ed3 = hex!("73736564207965740a497420697320616c736f206d7920726573706f6e736962").into();
550 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
551 let rsa2 = hex!("5468617420686176656e2774206265656e207061").into();
552 let rsa3 = hex!("696c69747920746f20616c65727420656163680a").into();
553
554 assert_sorted(&[
555 b(Some(ed1), None),
556 b(Some(ed2), None),
557 b(Some(ed3), None),
558 b(Some(ed3), Some(rsa1)),
559 ]);
560 assert_sorted(&[
561 b(Some(ed1), Some(rsa3)),
562 b(Some(ed2), Some(rsa2)),
563 b(Some(ed3), Some(rsa1)),
564 b(Some(ed3), Some(rsa2)),
565 ]);
566 assert_sorted(&[
567 b(Some(ed1), Some(rsa1)),
568 b(Some(ed1), Some(rsa2)),
569 b(Some(ed1), Some(rsa3)),
570 ]);
571 assert_sorted(&[
572 b(None, Some(rsa1)),
573 b(None, Some(rsa2)),
574 b(None, Some(rsa3)),
575 ]);
576 assert_sorted(&[
577 b(None, Some(rsa1)),
578 b(Some(ed1), None),
579 b(Some(ed1), Some(rsa1)),
580 ]);
581 }
582
583 #[test]
584 fn compare_id_sets() {
585 let ed1 = hex!("0a54686973206973207468652043656e7472616c205363727574696e697a6572").into();
587 let rsa1 = hex!("2e2e2e0a4974206973206d7920726573706f6e73").into();
588 let rsa2 = RsaIdentity::from(hex!("5468617420686176656e2774206265656e207061"));
589
590 let both1 = RelayIds::builder()
591 .ed_identity(ed1)
592 .rsa_identity(rsa1)
593 .build()
594 .unwrap();
595 let mixed = RelayIds::builder()
596 .ed_identity(ed1)
597 .rsa_identity(rsa2)
598 .build()
599 .unwrap();
600 let ed1 = RelayIds::builder().ed_identity(ed1).build().unwrap();
601 let rsa1 = RelayIds::builder().rsa_identity(rsa1).build().unwrap();
602 let rsa2 = RelayIds::builder().rsa_identity(rsa2).build().unwrap();
603
604 fn chk_equal(v: &impl HasRelayIds) {
605 assert!(v.same_relay_ids(v));
606 assert!(v.has_all_relay_ids_from(v));
607 assert!(v.has_any_relay_id_from(v));
608 }
609 fn chk_strict_subset(bigger: &impl HasRelayIds, smaller: &impl HasRelayIds) {
610 assert!(!bigger.same_relay_ids(smaller));
611 assert!(bigger.has_all_relay_ids_from(smaller));
612 assert!(bigger.has_any_relay_id_from(smaller));
613 assert!(!smaller.same_relay_ids(bigger));
614 assert!(!smaller.has_all_relay_ids_from(bigger));
615 assert!(smaller.has_any_relay_id_from(bigger));
616 }
617 fn chk_nontrivially_overlapping_one_way(a: &impl HasRelayIds, b: &impl HasRelayIds) {
618 assert!(!a.same_relay_ids(b));
619 assert!(!a.has_all_relay_ids_from(b));
620 assert!(a.has_any_relay_id_from(b));
621 }
622 fn chk_nontrivially_overlapping(a: &impl HasRelayIds, b: &impl HasRelayIds) {
623 chk_nontrivially_overlapping_one_way(a, b);
624 chk_nontrivially_overlapping_one_way(b, a);
625 }
626
627 chk_equal(&ed1);
628 chk_equal(&rsa1);
629 chk_equal(&both1);
630
631 chk_strict_subset(&both1, &ed1);
632 chk_strict_subset(&both1, &rsa1);
633 chk_strict_subset(&mixed, &ed1);
634 chk_strict_subset(&mixed, &rsa2);
635
636 chk_nontrivially_overlapping(&both1, &mixed);
637 }
638
639 #[test]
640 fn display() {
641 let e1 = example();
642 assert_eq!(
643 e1.display_chan_target().to_string(),
644 "[127.0.0.1:99+ ed25519:/FHNjmIYoaONpH7QAjDwWAgW7RO6MwOsXeuRFUiQgCU \
645 $1234567890abcdef12341234567890abcdef1234]"
646 );
647
648 #[cfg(feature = "pt-client")]
649 {
650 use crate::PtTarget;
651
652 let rsa = hex!("234461644a6f6b6523436f726e794f6e4d61696e").into();
653 let mut b = crate::OwnedChanTarget::builder();
654 b.ids().rsa_identity(rsa);
655 let e2 = b
656 .method(ChannelMethod::Pluggable(PtTarget::new(
657 "obfs4".parse().unwrap(),
658 "127.0.0.1:99".parse().unwrap(),
659 )))
660 .build()
661 .unwrap();
662 assert_eq!(
663 e2.to_string(),
664 "[127.0.0.1:99 via obfs4 $234461644a6f6b6523436f726e794f6e4d61696e]"
665 );
666 }
667 }
668
669 #[test]
670 fn has_id() {
671 use crate::RelayIds;
672 assert!(example().has_any_identity());
673 assert!(!RelayIds::empty().has_any_identity());
674 }
675}