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