1
//! Facilities to construct microdescriptor objects.
2
//!
3
//! (These are only for testing right now, since we don't yet
4
//! support encoding.)
5

            
6
use super::Microdesc;
7

            
8
use crate::types::family::RelayFamily;
9
use crate::types::policy::PortPolicy;
10
use crate::{BuildError as Error, BuildResult as Result, Error as ParseError};
11
use tor_llcrypto::pk::{curve25519, ed25519};
12

            
13
use rand::Rng;
14

            
15
/// A builder object used to construct a microdescriptor.
16
///
17
/// Create one of these with the [`Microdesc::builder`] method.
18
///
19
/// This facility is only enabled when the crate is built with
20
/// the `build_docs` feature.
21
#[derive(Debug, Clone)]
22
pub struct MicrodescBuilder {
23
    /// The ntor onion key we'll be using.
24
    ///
25
    /// See [`Microdesc::ntor_onion_key`].
26
    ntor_onion_key: Option<curve25519::PublicKey>,
27
    /// The relay family we'll be using.
28
    ///
29
    /// See [`Microdesc::family`].
30
    family: RelayFamily,
31
    /// See [`Microdesc::ipv4_policy`]
32
    ipv4_policy: PortPolicy,
33
    /// See [`Microdesc::ipv6_policy`]
34
    ipv6_policy: PortPolicy,
35
    /// See [`Microdesc::ed25519_id`]
36
    ed25519_id: Option<ed25519::Ed25519Identity>,
37
}
38

            
39
impl MicrodescBuilder {
40
    /// Create a new MicrodescBuilder.
41
37846
    pub(crate) fn new() -> Self {
42
37846
        MicrodescBuilder {
43
37846
            ntor_onion_key: None,
44
37846
            family: RelayFamily::new(),
45
37846
            ipv4_policy: PortPolicy::new_reject_all(),
46
37846
            ipv6_policy: PortPolicy::new_reject_all(),
47
37846
            ed25519_id: None,
48
37846
        }
49
37846
    }
50

            
51
    /// Set the ntor onion key.
52
    ///
53
    /// This key is required for a well-formed microdescriptor.
54
37726
    pub fn ntor_key(&mut self, key: curve25519::PublicKey) -> &mut Self {
55
37726
        self.ntor_onion_key = Some(key);
56
37726
        self
57
37726
    }
58

            
59
    /// Set the ed25519 identity key.
60
    ///
61
    /// This key is required for a well-formed microdescriptor.
62
37709
    pub fn ed25519_id(&mut self, key: ed25519::Ed25519Identity) -> &mut Self {
63
37709
        self.ed25519_id = Some(key);
64
37709
        self
65
37709
    }
66

            
67
    /// Set the family of this relay.
68
    ///
69
    /// By default, this family is empty.
70
37384
    pub fn family(&mut self, family: RelayFamily) -> &mut Self {
71
37384
        self.family = family;
72
37384
        self
73
37384
    }
74

            
75
    /// Set the ipv4 exit policy of this relay.
76
    ///
77
    /// By default, this policy is `reject 1-65535`.
78
38846
    pub fn ipv4_policy(&mut self, policy: PortPolicy) -> &mut Self {
79
38846
        self.ipv4_policy = policy;
80
38846
        self
81
38846
    }
82

            
83
    /// Set the ipv6 exit policy of this relay.
84
    ///
85
    /// By default, this policy is `reject 1-65535`.
86
681
    pub fn ipv6_policy(&mut self, policy: PortPolicy) -> &mut Self {
87
681
        self.ipv6_policy = policy;
88
681
        self
89
681
    }
90

            
91
    /// Set the family of this relay based on parsing a string.
92
1
    pub fn parse_family(&mut self, family: &str) -> Result<&mut Self> {
93
1
        Ok(self.family(family.parse()?))
94
1
    }
95

            
96
    /// Set the ipv4 exit policy of this relay based on parsing
97
    /// a string.
98
    ///
99
    /// By default, this policy is `reject 1-65535`.
100
38999
    pub fn parse_ipv4_policy(&mut self, policy: &str) -> Result<&mut Self> {
101
38999
        Ok(self.ipv4_policy(policy.parse().map_err(ParseError::from)?))
102
38999
    }
103

            
104
    /// Set the ipv6 exit policy of this relay based on parsing
105
    /// a string.
106
    ///
107
    /// By default, this policy is `reject 1-65535`.
108
681
    pub fn parse_ipv6_policy(&mut self, policy: &str) -> Result<&mut Self> {
109
681
        Ok(self.ipv6_policy(policy.parse().map_err(ParseError::from)?))
110
681
    }
111

            
112
    /// Try to build a microdescriptor from the settings on this builder.
113
    ///
114
    /// Give an error if any required fields are not set.
115
    ///
116
    /// # Limitations
117
    ///
118
    /// This is only for testing, since it does actually encode the
119
    /// information in a string, and since it sets the sha256 digest
120
    /// field at random.
121
    ///
122
    /// In the future, when we have authority support, we'll need an
123
    /// encoder function instead.
124
37523
    pub fn testing_md(&self) -> Result<Microdesc> {
125
37523
        let ntor_onion_key = self
126
37523
            .ntor_onion_key
127
37523
            .ok_or(Error::CannotBuild("Missing ntor_key"))?;
128
37522
        let ed25519_id = self
129
37522
            .ed25519_id
130
37522
            .ok_or(Error::CannotBuild("Missing ed25519_id"))?;
131

            
132
        // We generate a random sha256 value here, since this is only
133
        // for testing.
134
37453
        let sha256 = rand::thread_rng().gen();
135
37453

            
136
37453
        Ok(Microdesc {
137
37453
            sha256,
138
37453
            ntor_onion_key,
139
37453
            family: self.family.clone(),
140
37453
            ipv4_policy: self.ipv4_policy.clone().intern(),
141
37453
            ipv6_policy: self.ipv6_policy.clone().intern(),
142
37453
            ed25519_id,
143
37453
        })
144
37455
    }
145
}
146

            
147
#[cfg(test)]
148
mod test {
149
    #![allow(clippy::unwrap_used)]
150
    use super::*;
151

            
152
    #[test]
153
    fn minimal() {
154
        let ed: ed25519::Ed25519Identity = (*b"this is not much of a public key").into();
155
        let ntor: curve25519::PublicKey = (*b"but fortunately nothing cares...").into();
156

            
157
        let md = MicrodescBuilder::new()
158
            .ed25519_id(ed)
159
            .ntor_key(ntor)
160
            .testing_md()
161
            .unwrap();
162

            
163
        assert_eq!(md.ed25519_id(), &ed);
164
        assert_eq!(md.ntor_key(), &ntor);
165

            
166
        assert_eq!(md.family().members().count(), 0);
167
    }
168

            
169
    #[test]
170
    fn maximal() -> Result<()> {
171
        let ed: ed25519::Ed25519Identity = (*b"this is not much of a public key").into();
172
        let ntor: curve25519::PublicKey = (*b"but fortunately nothing cares...").into();
173

            
174
        let md = Microdesc::builder()
175
            .ed25519_id(ed)
176
            .ntor_key(ntor)
177
            .parse_ipv4_policy("accept 80,443")?
178
            .parse_ipv6_policy("accept 22-80")?
179
            .parse_family("$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa $bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")?
180
            .testing_md()
181
            .unwrap();
182

            
183
        assert_eq!(md.family().members().count(), 2);
184
        assert!(md.family().contains(&[0xaa; 20].into()));
185

            
186
        assert!(md.ipv4_policy().allows_port(443));
187
        assert!(md.ipv4_policy().allows_port(80));
188
        assert!(!md.ipv4_policy().allows_port(55));
189

            
190
        assert!(!md.ipv6_policy().allows_port(443));
191
        assert!(md.ipv6_policy().allows_port(80));
192
        assert!(md.ipv6_policy().allows_port(55));
193

            
194
        Ok(())
195
    }
196

            
197
    #[test]
198
    fn failing() {
199
        let ed: ed25519::Ed25519Identity = (*b"this is not much of a public key").into();
200
        let ntor: curve25519::PublicKey = (*b"but fortunately nothing cares...").into();
201

            
202
        {
203
            let mut builder = Microdesc::builder();
204
            builder.ed25519_id(ed);
205
            assert!(builder.testing_md().is_err()); // no ntor
206
        }
207

            
208
        {
209
            let mut builder = Microdesc::builder();
210
            builder.ntor_key(ntor);
211
            assert!(builder.testing_md().is_err()); // no ed id.
212
        }
213
    }
214
}