tor_guardmgr/
ids.rs

1//! Identifier objects used to specify guards and/or fallbacks.
2
3use derive_more::AsRef;
4use serde::{Deserialize, Serialize};
5use tor_linkspec::{HasRelayIds, RelayIds};
6#[cfg(test)]
7use tor_llcrypto::pk;
8
9use crate::GuardSetSelector;
10
11/// An identifier for a fallback directory cache.
12///
13/// This is a separate type from GuardId and FirstHopId to avoid confusion
14/// about what kind of object we're identifying.
15#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, AsRef)]
16pub(crate) struct FallbackId(pub(crate) RelayIds);
17
18impl FallbackId {
19    /// Return a new, manually constructed `FallbackId`
20    /// Extract a `FallbackId` from a ChanTarget object.
21    pub(crate) fn from_relay_ids<T>(target: &T) -> Self
22    where
23        T: tor_linkspec::HasRelayIds + ?Sized,
24    {
25        Self(RelayIds::from_relay_ids(target))
26    }
27}
28
29impl HasRelayIds for FallbackId {
30    fn identity(
31        &self,
32        key_type: tor_linkspec::RelayIdType,
33    ) -> Option<tor_linkspec::RelayIdRef<'_>> {
34        self.0.identity(key_type)
35    }
36}
37
38/// An identifier for a sampled guard.
39///
40/// This is a separate type from GuardId and FirstHopId to avoid confusion
41/// about what kind of object we're identifying.
42#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Ord, PartialOrd, AsRef)]
43#[serde(transparent)]
44pub(crate) struct GuardId(pub(crate) RelayIds);
45
46impl GuardId {
47    /// Return a new, manually constructed `GuardId`
48    #[cfg(test)]
49    pub(crate) fn new(ed25519: pk::ed25519::Ed25519Identity, rsa: pk::rsa::RsaIdentity) -> Self {
50        Self(
51            RelayIds::builder()
52                .ed_identity(ed25519)
53                .rsa_identity(rsa)
54                .build()
55                .expect("Couldn't build RelayIds"),
56        )
57    }
58    /// Extract a `GuardId` from a ChanTarget object.
59    pub(crate) fn from_relay_ids<T>(target: &T) -> Self
60    where
61        T: tor_linkspec::HasRelayIds + ?Sized,
62    {
63        Self(RelayIds::from_relay_ids(target))
64    }
65}
66
67impl HasRelayIds for GuardId {
68    fn identity(
69        &self,
70        key_type: tor_linkspec::RelayIdType,
71    ) -> Option<tor_linkspec::RelayIdRef<'_>> {
72        self.0.identity(key_type)
73    }
74}
75
76/// Implementation type held inside of FirstHopId.
77///
78/// This exists as a separate type from FirstHopId because Rust requires that a pub enum's variants are all public.
79#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
80pub(crate) enum FirstHopIdInner {
81    /// Identifies a guard.
82    Guard(GuardSetSelector, GuardId),
83    /// Identifies a fallback.
84    Fallback(FallbackId),
85}
86
87/// A unique cryptographic identifier for a selected guard or fallback
88/// directory.
89///
90/// (This is implemented internally using all of the guard's known identities.)
91#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
92pub struct FirstHopId(pub(crate) FirstHopIdInner);
93
94impl From<FallbackId> for FirstHopId {
95    fn from(id: FallbackId) -> Self {
96        Self(FirstHopIdInner::Fallback(id))
97    }
98}
99impl AsRef<RelayIds> for FirstHopId {
100    /// Return the inner `RelayIds` for this object.
101    ///
102    /// Only use this when it's okay to erase the type information about
103    /// whether this identifies a guard or a fallback.
104    fn as_ref(&self) -> &RelayIds {
105        match &self.0 {
106            FirstHopIdInner::Guard(_, id) => id.as_ref(),
107            FirstHopIdInner::Fallback(id) => id.as_ref(),
108        }
109    }
110}
111impl tor_linkspec::HasRelayIds for FirstHopId {
112    fn identity(
113        &self,
114        key_type: tor_linkspec::RelayIdType,
115    ) -> Option<tor_linkspec::RelayIdRef<'_>> {
116        self.as_ref().identity(key_type)
117    }
118}
119
120impl FirstHopId {
121    /// Return the relay in `netdir` that corresponds to this ID, if there
122    /// is one.
123    //
124    // We have to define this function so it'll be public.
125    pub fn get_relay<'a>(&self, netdir: &'a tor_netdir::NetDir) -> Option<tor_netdir::Relay<'a>> {
126        netdir.by_ids(self)
127    }
128
129    /// Construct a FirstHopId for a guard in a given sample.
130    pub(crate) fn in_sample(sample: GuardSetSelector, id: GuardId) -> Self {
131        Self(FirstHopIdInner::Guard(sample, id))
132    }
133}