1
//! Owned variants of [`ChanTarget`] and [`CircTarget`].
2

            
3
use safelog::Redactable;
4
use serde::{Deserialize, Serialize};
5
use std::fmt::{self, Display};
6
use std::net::SocketAddr;
7
use tor_config::impl_standard_builder;
8
use tor_llcrypto::pk;
9

            
10
use crate::{
11
    ChanTarget, ChannelMethod, CircTarget, HasAddrs, HasChanMethod, HasRelayIds, RelayIdRef,
12
    RelayIdType,
13
};
14

            
15
/// RelayIds is an owned copy of the set of known identities of a relay.
16
///
17
/// Note that an object of this type will not necessarily have every type of
18
/// identity: it's possible that we don't know all the identities, or that one
19
/// of the identity types has become optional.
20
#[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))]
33
pub struct RelayIds {
34
    /// Copy of the ed25519 id from the underlying ChanTarget.
35
    #[serde(rename = "ed25519")]
36
    #[builder(default, setter(strip_option))]
37
    ed_identity: Option<pk::ed25519::Ed25519Identity>,
38
    /// Copy of the rsa id from the underlying ChanTarget.
39
    #[serde(rename = "rsa")]
40
    #[builder(default, setter(strip_option))]
41
    rsa_identity: Option<pk::rsa::RsaIdentity>,
42
}
43
impl_standard_builder! { RelayIds : !Deserialize + !Builder + !Default }
44

            
45
impl HasRelayIds for RelayIds {
46
124240195
    fn identity(&self, key_type: RelayIdType) -> Option<crate::RelayIdRef<'_>> {
47
124240195
        match key_type {
48
68957591
            RelayIdType::Ed25519 => self.ed_identity.as_ref().map(RelayIdRef::from),
49
55282604
            RelayIdType::Rsa => self.rsa_identity.as_ref().map(RelayIdRef::from),
50
        }
51
124240195
    }
52
}
53

            
54
impl RelayIds {
55
    /// Return an empty set of identities.
56
    ///
57
    /// This is _not_ a `Default` method, since this is not what you should
58
    /// usually construct.
59
5375
    pub const fn empty() -> Self {
60
5375
        Self {
61
5375
            ed_identity: None,
62
5375
            rsa_identity: None,
63
5375
        }
64
5375
    }
65

            
66
    /// Construct a new `RelayIds` object from another object that implements
67
    /// [`HasRelayIds`].
68
    ///
69
    /// Note that it is possible to construct an _empty_ `RelayIds` object if
70
    /// the input does not contain any recognized identity type.
71
3739146
    pub fn from_relay_ids<T: HasRelayIds + ?Sized>(other: &T) -> Self {
72
        Self {
73
3739146
            ed_identity: other
74
3739146
                .identity(RelayIdType::Ed25519)
75
3739146
                .map(|r| *r.unwrap_ed25519()),
76
3739146
            rsa_identity: other.identity(RelayIdType::Rsa).map(|r| *r.unwrap_rsa()),
77
        }
78
3739146
    }
79
}
80

            
81
impl std::fmt::Display for RelayIds {
82
1241
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83
1241
        write!(f, "{}", self.display_relay_ids())
84
1241
    }
85
}
86
impl Redactable for RelayIds {
87
2
    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88
2
        write!(f, "{}", self.display_relay_ids().redacted())
89
2
    }
90
}
91

            
92
impl RelayIdsBuilder {
93
    /// Construct a new `RelayIdsBuilder` object from an object implementing
94
    /// [`HasRelayIds`].
95
    ///
96
    /// Note that it is possible to construct an _empty_ `RelayIds` object if
97
    /// the input does not contain any recognized identity type.
98
50
    pub fn from_relay_ids<T: HasRelayIds + ?Sized>(ids: &T) -> Self {
99
50
        let mut builder = Self::default();
100
50
        if let Some(ed_id) = ids.ed_identity() {
101
48
            builder.ed_identity(*ed_id);
102
50
        }
103
50
        if let Some(rsa_id) = ids.rsa_identity() {
104
48
            builder.rsa_identity(*rsa_id);
105
50
        }
106
50
        builder
107
50
    }
108
}
109

            
110
/// OwnedChanTarget is a summary of a [`ChanTarget`] that owns all of its
111
/// members.
112
#[derive(Debug, Clone, derive_builder::Builder)]
113
#[builder(derive(Debug))]
114
pub struct OwnedChanTarget {
115
    /// Copy of the addresses from the underlying ChanTarget.
116
    #[builder(default)]
117
    addrs: Vec<SocketAddr>,
118
    /// Copy of the channel methods from the underlying ChanTarget.
119
    //
120
    // TODO: in many cases this will be redundant with addrs; if we allocate a
121
    // lot of these objects, we might want to handle that.
122
    #[builder(default = "self.make_method()")]
123
    method: ChannelMethod,
124
    /// Identities that this relay provides.
125
    #[builder(sub_builder)]
126
    ids: RelayIds,
127
}
128
impl_standard_builder! { OwnedChanTarget : !Deserialize + !Builder + !Default }
129

            
130
impl OwnedChanTargetBuilder {
131
    /// Set the ed25519 identity in this builder to `id`.
132
49574
    pub fn ed_identity(&mut self, id: pk::ed25519::Ed25519Identity) -> &mut Self {
133
49574
        self.ids().ed_identity(id);
134
49574
        self
135
49574
    }
136

            
137
    /// Set the RSA identity in this builder to `id`.
138
48394
    pub fn rsa_identity(&mut self, id: pk::rsa::RsaIdentity) -> &mut Self {
139
48394
        self.ids().rsa_identity(id);
140
48394
        self
141
48394
    }
142

            
143
    /// Helper: make a channel method if none was specified.
144
49806
    fn make_method(&self) -> ChannelMethod {
145
49806
        ChannelMethod::Direct(self.addrs.clone().unwrap_or_default())
146
49806
    }
147
}
148

            
149
impl HasAddrs for OwnedChanTarget {
150
186043
    fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
151
186043
        self.addrs.iter().copied()
152
186043
    }
153
}
154

            
155
impl HasChanMethod for OwnedChanTarget {
156
188690
    fn chan_method(&self) -> ChannelMethod {
157
188690
        self.method.clone()
158
188690
    }
159
}
160

            
161
impl HasRelayIds for OwnedChanTarget {
162
9813333
    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
163
9813333
        self.ids.identity(key_type)
164
9813333
    }
165
}
166

            
167
impl ChanTarget for OwnedChanTarget {}
168

            
169
impl OwnedChanTarget {
170
    /// Construct a OwnedChanTarget from a given ChanTarget.
171
2321542
    pub fn from_chan_target<C>(target: &C) -> Self
172
2321542
    where
173
2321542
        C: ChanTarget + ?Sized,
174
    {
175
2321542
        OwnedChanTarget {
176
2321542
            addrs: target.addrs().collect(),
177
2321542
            method: target.chan_method(),
178
2321542
            ids: RelayIds::from_relay_ids(target),
179
2321542
        }
180
2321542
    }
181

            
182
    /// Return a mutable reference to this [`OwnedChanTarget`]'s [`ChannelMethod`]
183
    ///
184
354
    pub fn chan_method_mut(&mut self) -> &mut ChannelMethod {
185
354
        &mut self.method
186
354
    }
187
}
188

            
189
/// Primarily for error reporting and logging
190
impl Display for OwnedChanTarget {
191
2
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192
2
        write!(f, "{}", self.display_chan_target())
193
2
    }
194
}
195

            
196
impl Redactable for OwnedChanTarget {
197
    fn display_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198
        self.display_chan_target().display_redacted(f)
199
    }
200

            
201
    fn debug_redacted(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202
        self.display_chan_target().debug_redacted(f)
203
    }
204
}
205

            
206
/// OwnedCircTarget is a summary of a [`CircTarget`] that owns all its
207
/// members.
208
#[derive(Debug, Clone, derive_builder::Builder)]
209
#[builder(derive(Debug))]
210
pub struct OwnedCircTarget {
211
    /// The fields from this object when considered as a ChanTarget.
212
    #[builder(sub_builder)]
213
    chan_target: OwnedChanTarget,
214
    /// The ntor key to use when extending to this CircTarget
215
    ntor_onion_key: pk::curve25519::PublicKey,
216
    /// The subprotocol versions that this CircTarget supports.
217
    protocols: tor_protover::Protocols,
218
}
219
impl_standard_builder! { OwnedCircTarget : !Deserialize + !Builder + !Default }
220

            
221
impl OwnedCircTarget {
222
    /// Construct an OwnedCircTarget from a given CircTarget.
223
78464
    pub fn from_circ_target<C>(target: &C) -> Self
224
78464
    where
225
78464
        C: CircTarget + ?Sized,
226
    {
227
78464
        OwnedCircTarget {
228
78464
            chan_target: OwnedChanTarget::from_chan_target(target),
229
78464
            ntor_onion_key: *target.ntor_onion_key(),
230
78464
            protocols: target.protovers().clone(),
231
78464
        }
232
78464
    }
233

            
234
    /// Return a mutable view of this OwnedCircTarget as an [`OwnedChanTarget`].
235
    pub fn chan_target_mut(&mut self) -> &mut OwnedChanTarget {
236
        &mut self.chan_target
237
    }
238

            
239
    /// Return a  view of this OwnedCircTarget as an [`OwnedChanTarget`].
240
354
    pub fn chan_target(&self) -> &OwnedChanTarget {
241
354
        &self.chan_target
242
354
    }
243
}
244

            
245
impl HasAddrs for OwnedCircTarget {
246
2368
    fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
247
2368
        self.chan_target.addrs()
248
2368
    }
249
}
250

            
251
impl HasRelayIds for OwnedCircTarget {
252
4515054
    fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
253
4515054
        self.chan_target.identity(key_type)
254
4515054
    }
255
}
256
impl HasChanMethod for OwnedCircTarget {
257
4488
    fn chan_method(&self) -> ChannelMethod {
258
4488
        self.chan_target.chan_method()
259
4488
    }
260
}
261

            
262
impl ChanTarget for OwnedCircTarget {}
263

            
264
impl CircTarget for OwnedCircTarget {
265
3430
    fn ntor_onion_key(&self) -> &pk::curve25519::PublicKey {
266
3430
        &self.ntor_onion_key
267
3430
    }
268
3430
    fn protovers(&self) -> &tor_protover::Protocols {
269
3430
        &self.protocols
270
3430
    }
271
}
272

            
273
/// A value that can be converted into an OwnedChanTarget.
274
pub trait IntoOwnedChanTarget {
275
    /// Convert this value into an [`OwnedChanTarget`].
276
    fn to_owned(self) -> OwnedChanTarget;
277

            
278
    /// Convert this value into an [`LoggedChanTarget`].
279
    fn to_logged(self) -> LoggedChanTarget
280
    where
281
        Self: Sized,
282
    {
283
        self.to_owned().into()
284
    }
285
}
286

            
287
impl<'a, T: ChanTarget + ?Sized> IntoOwnedChanTarget for &'a T {
288
    fn to_owned(self) -> OwnedChanTarget {
289
        OwnedChanTarget::from_chan_target(self)
290
    }
291
}
292

            
293
impl IntoOwnedChanTarget for OwnedChanTarget {
294
    fn to_owned(self) -> OwnedChanTarget {
295
        self
296
    }
297
}
298

            
299
/// An `OwnedChanTarget` suitable for logging and including in errors
300
pub type LoggedChanTarget = safelog::BoxSensitive<OwnedChanTarget>;
301

            
302
#[cfg(test)]
303
mod test {
304
    // @@ begin test lint list maintained by maint/add_warning @@
305
    #![allow(clippy::bool_assert_comparison)]
306
    #![allow(clippy::clone_on_copy)]
307
    #![allow(clippy::dbg_macro)]
308
    #![allow(clippy::mixed_attributes_style)]
309
    #![allow(clippy::print_stderr)]
310
    #![allow(clippy::print_stdout)]
311
    #![allow(clippy::single_char_pattern)]
312
    #![allow(clippy::unwrap_used)]
313
    #![allow(clippy::unchecked_time_subtraction)]
314
    #![allow(clippy::useless_vec)]
315
    #![allow(clippy::needless_pass_by_value)]
316
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
317
    use super::*;
318
    use itertools::Itertools;
319

            
320
    #[test]
321
    #[allow(clippy::redundant_clone)]
322
    fn chan_target() {
323
        let ti = OwnedChanTarget::builder()
324
            .addrs(vec!["127.0.0.1:11".parse().unwrap()])
325
            .ed_identity([42; 32].into())
326
            .rsa_identity([45; 20].into())
327
            .build()
328
            .unwrap();
329

            
330
        let ti2 = OwnedChanTarget::from_chan_target(&ti);
331
        assert_eq!(ti.addrs().collect_vec(), ti2.addrs().collect_vec());
332
        assert!(ti.same_relay_ids(&ti2));
333

            
334
        assert_eq!(format!("{:?}", ti), format!("{:?}", ti2));
335
        assert_eq!(format!("{:?}", ti), format!("{:?}", ti.clone()));
336
    }
337

            
338
    #[test]
339
    #[allow(clippy::redundant_clone)]
340
    fn circ_target() {
341
        let mut builder = OwnedCircTarget::builder();
342
        builder
343
            .chan_target()
344
            .addrs(vec!["127.0.0.1:11".parse().unwrap()])
345
            .ed_identity([42; 32].into())
346
            .rsa_identity([45; 20].into());
347
        let ct = builder
348
            .ntor_onion_key([99; 32].into())
349
            .protocols("FlowCtrl=7".parse().unwrap())
350
            .build()
351
            .unwrap();
352
        let ch = ct.chan_target.clone();
353

            
354
        assert_eq!(ct.addrs().collect_vec(), ch.addrs().collect_vec());
355
        assert!(ct.same_relay_ids(&ch));
356
        assert_eq!(ct.ntor_onion_key().as_bytes(), &[99; 32]);
357
        assert_eq!(&ct.protovers().to_string(), "FlowCtrl=7");
358
        let ct2 = OwnedCircTarget::from_circ_target(&ct);
359
        assert_eq!(format!("{:?}", ct), format!("{:?}", ct2));
360
        assert_eq!(format!("{:?}", ct), format!("{:?}", ct.clone()));
361
    }
362

            
363
    #[test]
364
    fn format_relay_ids() {
365
        let mut builder = RelayIds::builder();
366
        builder
367
            .ed_identity([42; 32].into())
368
            .rsa_identity([45; 20].into());
369
        let ids = builder.build().unwrap();
370
        assert_eq!(
371
            format!("{}", ids),
372
            "ed25519:KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKio $2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d"
373
        );
374
        assert_eq!(format!("{}", ids.redacted()), "ed25519:Ki…");
375
    }
376
}