dsf_core/base/
body.rs

1//! Base object is a common owned object that is used to represent pages / messages / data
2//! and can be encoded and decoded for wire communication.
3
4#[cfg(feature = "alloc")]
5use alloc::prelude::v1::*;
6
7use crate::base::Header;
8use crate::error::Error;
9use crate::options::{Options, OptionsError};
10use crate::types::*;
11use crate::wire::Container;
12
13#[derive(Clone, Debug)]
14pub struct Base {
15    /// Page or Object Identifier
16    pub(crate) id: Id,
17
18    /// Header contains object parsing information and flags
19    pub(crate) header: Header,
20
21    /// Body contains arbitrary service data for Pages, Blocks, and Messages
22    pub(crate) body: Body,
23
24    /// Private options supports the addition of options that are only visible
25    /// to authorized service consumers
26    pub(crate) private_options: PrivateOptions,
27
28    /// Public options provide a simple mechanism for extension of objects
29    pub(crate) public_options: Vec<Options>,
30
31    /// Page parent / previous page link
32    /// Used for constructing a hash-chain of published objects and included as a public option
33    /// This is automatically included / extracted to simplify higher level parsing
34    pub(crate) parent: Option<Signature>,
35
36    /// Service public key
37    /// Used to support self-signed objects and included as a public option
38    /// This is automatically included / extracted to simplify higher level parsing
39    pub(crate) public_key: Option<PublicKey>,
40
41    /// Object PeerID
42    /// Used to support secondary objects and included as a public option
43    /// This is automatically included / extracted to simplify higher level parsing
44    pub(crate) peer_id: Option<Id>,
45
46    /// Object signature
47    pub(crate) signature: Option<Signature>,
48
49    /// Verified flag indicates object signature verification status
50    pub(crate) verified: bool,
51
52    /// Raw object container, used to avoid re-encoding objects
53    pub(crate) raw: Option<Vec<u8>>,
54}
55
56/// Options for constructing base objects
57pub struct BaseOptions {
58    /// Private / encrypted options
59    pub private_options: PrivateOptions,
60    /// Public / plaintext options
61    pub public_options: Vec<Options>,
62    /// Parent object signature
63    pub parent: Option<Signature>,
64    /// Parent service public key
65    pub public_key: Option<PublicKey>,
66    /// Peer ID for secondary object mapping
67    pub peer_id: Option<Id>,
68    /// Object signature
69    pub signature: Option<Signature>,
70    /// Raw / pre-encoded object data
71    pub raw: Option<Vec<u8>>,
72}
73
74impl Default for BaseOptions {
75    fn default() -> Self {
76        Self {
77            private_options: PrivateOptions::None,
78            public_options: vec![],
79            parent: None,
80            public_key: None,
81            peer_id: None,
82            signature: None,
83            raw: None,
84        }
85    }
86}
87
88impl BaseOptions {
89    pub fn append_public_option(&mut self, o: Options) -> &mut Self {
90        self.public_options.push(o);
91        self
92    }
93
94    pub fn append_private_option(&mut self, o: Options) -> &mut Self {
95        match &mut self.private_options {
96            PrivateOptions::Cleartext(opts) => opts.push(o),
97            _ => self.private_options = PrivateOptions::Cleartext(vec![o]),
98        }
99        self
100    }
101}
102
103impl PartialEq for Base {
104    fn eq(&self, other: &Self) -> bool {
105        self.id == other.id
106            && self.header == other.header
107            && self.body == other.body
108            && self.private_options == other.private_options
109            && self.public_options == other.public_options
110            && self.parent == other.parent
111            && self.public_key == other.public_key
112            && self.peer_id == other.peer_id
113            && self.signature == other.signature
114    }
115}
116
117#[derive(PartialEq, Debug, Clone)]
118#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
119pub enum NewBody<T: ImmutableData> {
120    Cleartext(T),
121    Encrypted(T),
122    None,
123}
124
125impl Body {
126    /// Decrypt an object body with the provided secret key
127    pub fn decrypt(&mut self, secret_key: Option<&SecretKey>) -> Result<(), Error> {
128        let body = match (&self, &secret_key) {
129            (NewBody::Cleartext(b), _) => b.to_vec(),
130            (NewBody::Encrypted(e), Some(sk)) => {
131                let mut d = e.to_vec();
132
133                let n = match crate::crypto::sk_decrypt2(sk, &mut d) {
134                    Ok(n) => n,
135                    Err(_) => return Err(Error::SecretKeyMismatch),
136                };
137
138                d.truncate(n);
139
140                d
141            }
142            _ => return Err(Error::NoSecretKey),
143        };
144
145        *self = Self::Cleartext(body);
146
147        Ok(())
148    }
149}
150
151/// Body may be empty, encrypted, or Cleartext
152// TODO: move NewBody from wire to here, propagate generic types
153pub type Body = NewBody<Vec<u8>>;
154
155impl From<Vec<u8>> for Body {
156    fn from(o: Vec<u8>) -> Self {
157        if o.len() > 0 {
158            Body::Cleartext(o)
159        } else {
160            Body::None
161        }
162    }
163}
164
165impl From<Option<Body>> for Body {
166    fn from(o: Option<Body>) -> Self {
167        match o {
168            Some(b) => b,
169            None => Body::None,
170        }
171    }
172}
173
174//pub type OptionsList = crate::wire::builder::OptionsList<Vec<Options>, Vec<u8>>;
175pub type PrivateOptions = crate::options::OptionsList<Vec<Options>, Vec<u8>>;
176
177impl From<Vec<Options>> for PrivateOptions {
178    fn from(o: Vec<Options>) -> Self {
179        if o.len() > 0 {
180            PrivateOptions::Cleartext(o)
181        } else {
182            PrivateOptions::None
183        }
184    }
185}
186
187impl PrivateOptions {
188    pub fn append(&mut self, o: Options) {
189        match self {
190            PrivateOptions::Cleartext(opts) => opts.push(o),
191            PrivateOptions::None => *self = PrivateOptions::Cleartext(vec![o]),
192            _ => panic!("attmepting to append private options to encrypted object"),
193        }
194    }
195}
196
197#[derive(PartialEq, Debug, Clone)]
198#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
199pub enum BaseError {
200    Io,
201    Options(OptionsError),
202    InvalidSignature,
203    NoPublicKey,
204    NoPrivateKey,
205    NoPeerId,
206    ValidateError,
207    DecryptError,
208    NoDecryptionKey,
209    PublicKeyIdMismatch,
210}
211
212use crate::net;
213use crate::page;
214
215pub enum Parent<'a, 'b, 'c> {
216    None,
217    Page(&'a page::Page),
218    Request(&'b net::Request),
219    Response(&'c net::Response),
220}
221
222impl From<OptionsError> for BaseError {
223    fn from(o: OptionsError) -> BaseError {
224        BaseError::Options(o)
225    }
226}
227
228#[cfg(feature = "std")]
229impl From<std::io::Error> for BaseError {
230    fn from(e: std::io::Error) -> BaseError {
231        error!("io error: {}", e);
232        BaseError::Io
233    }
234}
235
236impl Base {
237    /// Create a new base object the provided options
238    pub fn new(id: Id, header: Header, body: Body, options: BaseOptions) -> Self {
239        Self {
240            id,
241            header,
242            body,
243            private_options: options.private_options,
244            public_options: options.public_options,
245            parent: options.parent,
246            public_key: options.public_key,
247            peer_id: options.peer_id,
248            signature: options.signature,
249            verified: false,
250            raw: options.raw,
251        }
252    }
253
254    pub fn id(&self) -> &Id {
255        &self.id
256    }
257
258    pub fn header(&self) -> &Header {
259        &self.header
260    }
261
262    pub fn flags(&self) -> Flags {
263        self.header.flags()
264    }
265
266    pub fn body(&self) -> &Body {
267        &self.body
268    }
269
270    pub fn public_options(&self) -> &[Options] {
271        &self.public_options
272    }
273
274    pub fn private_options(&self) -> &PrivateOptions {
275        &self.private_options
276    }
277
278    pub fn signature(&self) -> &Option<Signature> {
279        &self.signature
280    }
281
282    pub fn set_signature(&mut self, sig: Signature) {
283        self.signature = Some(sig);
284    }
285
286    pub fn append_public_option(&mut self, o: Options) {
287        self.public_options.push(o);
288    }
289
290    pub fn append_private_option(&mut self, o: Options) {
291        match &mut self.private_options {
292            PrivateOptions::Cleartext(opts) => opts.push(o),
293            PrivateOptions::None => self.private_options = PrivateOptions::Cleartext(vec![o]),
294            _ => panic!("attmepting to append private options to encrypted object"),
295        }
296    }
297
298    pub fn clean(&mut self) {}
299}
300
301// TODO: move these to the options module?
302impl Base {
303    pub fn pub_key_option(options: &[Options]) -> Option<PublicKey> {
304        options.iter().find_map(|o| match o {
305            Options::PubKey(pk) => Some(pk.public_key.clone()),
306            _ => None,
307        })
308    }
309
310    pub fn peer_id_option(options: &[Options]) -> Option<Id> {
311        options.iter().find_map(|o| match o {
312            Options::PeerId(peer_id) => Some(peer_id.peer_id.clone()),
313            _ => None,
314        })
315    }
316
317    pub fn issued_option(options: &[Options]) -> Option<DateTime> {
318        options.iter().find_map(|o| match o {
319            Options::Issued(t) => Some(t.when),
320            _ => None,
321        })
322    }
323
324    pub fn expiry_option(options: &[Options]) -> Option<DateTime> {
325        options.iter().find_map(|o| match o {
326            Options::Expiry(t) => Some(t.when),
327            _ => None,
328        })
329    }
330
331    pub fn prev_sig_option(options: &[Options]) -> Option<Signature> {
332        options.iter().find_map(|o| match o {
333            Options::PrevSig(s) => Some(s.sig.clone()),
334            _ => None,
335        })
336    }
337
338    pub fn address_option(options: &[Options]) -> Option<Address> {
339        options.iter().find_map(|o| match o {
340            Options::IPv4(addr) => Some(addr.clone().into()),
341            Options::IPv6(addr) => Some(addr.clone().into()),
342            _ => None,
343        })
344    }
345
346    pub fn raw(&self) -> &Option<Vec<u8>> {
347        &self.raw
348    }
349
350    pub fn set_raw(&mut self, raw: Vec<u8>) {
351        self.raw = Some(raw);
352    }
353}
354
355impl Base {
356    /// Parses a data array into a base object using the pubkey_source to locate
357    /// a key for validation
358    pub fn parse<'a, P, S, T: AsRef<[u8]>>(
359        data: T,
360        pub_key_s: P,
361        sec_key_s: S,
362    ) -> Result<(Base, usize), BaseError>
363    where
364        P: FnMut(&Id) -> Option<PublicKey>,
365        S: FnMut(&Id) -> Option<SecretKey>,
366    {
367        Container::parse(data, pub_key_s, sec_key_s)
368    }
369}
370
371impl Base {
372    pub fn encode<'a, T: AsRef<[u8]> + AsMut<[u8]>>(
373        &mut self,
374        signing_key: Option<&PrivateKey>,
375        encryption_key: Option<&SecretKey>,
376        mut buff: T,
377    ) -> Result<usize, BaseError> {
378        // Short circuit if raw object is available
379        if let Some(raw) = &self.raw {
380            let d = buff.as_mut();
381
382            &mut d[0..raw.len()].copy_from_slice(&raw);
383
384            return Ok(raw.len());
385        }
386
387        let signing_key = match signing_key {
388            Some(k) => k,
389            None => return Err(BaseError::NoPrivateKey),
390        };
391
392        // Build container and encode / encrypt / sign page
393        let (container, n) = Container::encode(buff, &self, signing_key, encryption_key);
394
395        // Update base object signature
396        self.set_signature(container.signature().into());
397
398        Ok(n)
399    }
400}
401
402#[cfg(test)]
403mod tests {
404
405    use super::*;
406    use crate::base::*;
407    use crate::types::PageKind;
408
409    use crate::crypto;
410
411    fn setup() -> (Id, PublicKey, PrivateKey, SecretKey) {
412        let (pub_key, pri_key) =
413            crypto::new_pk().expect("Error generating new public/private key pair");
414        let id = crypto::hash(&pub_key)
415            .expect("Error generating new ID")
416            .into();
417        let sec_key = crypto::new_sk().expect("Error generating new secret key");
418        (id, pub_key, pri_key, sec_key)
419    }
420
421    #[test]
422    fn encode_decode_primary_page() {
423        let (id, pub_key, pri_key, _sec_key) = setup();
424
425        let header = Header {
426            kind: PageKind::Generic.into(),
427            ..Default::default()
428        };
429        let data = vec![1, 2, 3, 4, 5, 6, 7];
430
431        let mut page = Base::new(id, header, Body::Cleartext(data), BaseOptions::default());
432
433        let mut buff = vec![0u8; 1024];
434        let n = page
435            .encode(Some(&pri_key), None, &mut buff)
436            .expect("Error encoding page");
437
438        let (mut decoded, m) = Base::parse(&buff[..n], |_id| Some(pub_key.clone()), |_id| None)
439            .expect("Error decoding page");
440
441        decoded.clean();
442
443        assert_eq!(page, decoded);
444        assert_eq!(n, m);
445    }
446
447    #[test]
448    fn encode_decode_secondary_page() {
449        let (id, pub_key, pri_key, _sec_key) = setup();
450
451        let header = Header {
452            kind: PageKind::Replica.into(),
453            flags: Flags::SECONDARY,
454            ..Default::default()
455        };
456        let data = vec![1, 2, 3, 4, 5, 6, 7];
457
458        let mut page = Base::new(
459            id.clone(),
460            header,
461            Body::Cleartext(data),
462            BaseOptions {
463                peer_id: Some(id.clone()),
464                public_key: Some(pub_key.clone()),
465                ..Default::default()
466            },
467        );
468
469        let mut buff = vec![0u8; 1024];
470        let n = page
471            .encode(Some(&pri_key), None, &mut buff)
472            .expect("Error encoding page");
473        page.raw = Some(buff[..n].to_vec());
474
475        let (mut decoded, m) = Base::parse(&buff[..n], |_id| Some(pub_key.clone()), |_id| None)
476            .expect("Error decoding page with known public key");
477
478        decoded.clean();
479        assert_eq!(page, decoded);
480        assert_eq!(n, m);
481
482        let (mut decoded, m) = Base::parse(&buff[..n], |_id| None, |_id| None)
483            .expect("Error decoding page with unknown public key");
484
485        decoded.clean();
486        assert_eq!(page, decoded);
487        assert_eq!(n, m);
488    }
489
490    #[test]
491    fn encode_decode_encrypted_page() {
492        let (id, pub_key, pri_key, sec_key) = setup();
493
494        let header = Header {
495            kind: PageKind::Generic.into(),
496            flags: Flags::ENCRYPTED,
497            ..Default::default()
498        };
499        let data = vec![1, 2, 3, 4, 5, 6, 7];
500
501        let mut page = Base::new(id, header, Body::Cleartext(data), BaseOptions::default());
502
503        let mut buff = vec![0u8; 1024];
504        let n = page
505            .encode(Some(&pri_key), Some(&sec_key), &mut buff)
506            .expect("Error encoding page");
507
508        let (mut decoded, m) = Base::parse(
509            &buff[..n],
510            |_id| Some(pub_key.clone()),
511            |_id| Some(sec_key.clone()),
512        )
513        .expect("Error decoding page");
514
515        decoded.clean();
516
517        assert_eq!(page, decoded);
518        assert_eq!(n, m);
519    }
520}