1use core::convert::TryFrom;
5
6#[cfg(feature = "alloc")]
7use alloc::prelude::v1::*;
8
9use crate::base::{Base, BaseOptions, Body, Header, PrivateOptions};
10use crate::crypto;
11use crate::error::Error;
12use crate::options::Options;
13use crate::types::*;
14
15mod info;
16pub use info::PageInfo;
17
18#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
23#[derive(Debug, Clone)]
24pub struct Page {
25 pub id: Id,
27
28 pub header: Header,
30
31 pub info: PageInfo,
33
34 pub body: Body,
36
37 pub issued: Option<DateTime>,
39 pub expiry: Option<DateTime>,
40
41 pub public_options: Vec<Options>,
42
43 pub private_options: PrivateOptions,
44
45 pub previous_sig: Option<Signature>,
47
48 pub signature: Option<Signature>,
50
51 pub verified: bool,
53
54 pub raw: Option<Vec<u8>>,
56
57 _extend: (),
58}
59
60#[derive(Debug, Clone, PartialEq)]
61pub struct PageOptions {
62 pub issued: Option<DateTime>,
64 pub expiry: Option<DateTime>,
66
67 pub public_options: Vec<Options>,
69 pub private_options: PrivateOptions,
71
72 pub previous_sig: Option<Signature>,
74 pub signature: Option<Signature>,
76 pub raw: Option<Vec<u8>>,
78}
79
80impl Default for PageOptions {
81 fn default() -> Self {
82 Self {
83 issued: None,
84 expiry: None,
85 public_options: vec![],
86 private_options: PrivateOptions::None,
87 previous_sig: None,
88 signature: None,
89 raw: None,
90 }
91 }
92}
93
94impl PartialEq for Page {
95 fn eq(&self, o: &Self) -> bool {
96 self.id == o.id
97 && self.header == o.header
98 && self.info == o.info
99 && self.body == o.body
100 && self.issued == o.issued
101 && self.expiry == o.expiry
102 && self.previous_sig == o.previous_sig
103 && self.public_options == o.public_options
104 && self.private_options == o.private_options
105 && self.signature == o.signature
106 }
107}
108
109impl Page {
110 pub fn new(id: Id, header: Header, info: PageInfo, body: Body, options: PageOptions) -> Self {
112 Page {
113 id,
114 header,
115 info,
116 body,
117
118 issued: options.issued,
119 expiry: options.expiry,
120
121 public_options: options.public_options,
122 private_options: options.private_options,
123
124 previous_sig: options.previous_sig,
125
126 signature: options.signature,
127 raw: options.raw,
128
129 verified: false,
130
131 _extend: (),
132 }
133 }
134
135 pub fn id(&self) -> &Id {
136 &self.id
137 }
138
139 pub fn header(&self) -> &Header {
140 &self.header
141 }
142
143 pub fn info(&self) -> &PageInfo {
144 &self.info
145 }
146
147 pub fn body(&self) -> &Body {
148 &self.body
149 }
150
151 pub fn issued(&self) -> Option<DateTime> {
152 self.issued
153 }
154
155 pub fn expiry(&self) -> Option<DateTime> {
156 self.expiry
157 }
158
159 #[cfg(feature = "std")]
160 pub fn valid(&self) -> bool {
161 use std::ops::Add;
162
163 let (issued, expiry): (Option<std::time::SystemTime>, Option<std::time::SystemTime>) = (
165 self.issued().map(|v| v.into()),
166 self.expiry().map(|v| v.into()),
167 );
168
169 match (issued, expiry) {
171 (_, Some(expiry)) => std::time::SystemTime::now() > expiry,
173 (Some(issued), None) => {
175 std::time::SystemTime::now() < issued.add(std::time::Duration::from_secs(3600))
176 }
177 _ => true,
180 }
181 }
182
183 pub fn public_options(&self) -> &[Options] {
184 &self.public_options
185 }
186
187 pub fn private_options(&self) -> &PrivateOptions {
188 &self.private_options
189 }
190
191 pub fn signature(&self) -> Option<Signature> {
192 self.signature.clone()
193 }
194
195 pub fn set_signature(&mut self, sig: Signature) {
196 self.signature = Some(sig);
197 }
198
199 pub fn raw(&self) -> &Option<Vec<u8>> {
200 &self.raw
201 }
202
203 pub fn clean(&mut self) {
204 self.raw = None;
205 }
206}
207
208impl Page {
209 pub fn decode_pages<V>(buff: &[u8], key_source: V) -> Result<Vec<Page>, Error>
210 where
211 V: Fn(&Id) -> Option<PublicKey>,
212 {
213 let mut pages = vec![];
214 let mut i = 0;
215
216 let mut last_key: Option<(Id, PublicKey)> = None;
218
219 while i < buff.len() {
220 let (b, n) = Base::parse(
222 &buff[i..],
223 |id| {
224 if let Some(key) = (key_source)(id) {
226 return Some(key);
227 };
228
229 if let Some(prev) = &last_key {
231 if &prev.0 == id {
232 return Some(prev.1.clone());
233 }
234 }
235
236 None
238 },
239 |_id| None,
241 )?;
242
243 i += n;
244
245 let page = match Page::try_from(b) {
246 Ok(p) => p,
247 Err(e) => {
248 error!("Error loading page from message: {:?}", e);
249 continue;
250 }
251 };
252
253 if let Some(key) = page.info().pub_key() {
255 last_key = Some((page.id().clone(), key));
256 }
257
258 pages.push(page);
260 }
261
262 Ok(pages)
263 }
264
265 pub fn encode_pages(pages: &[Page], buff: &mut [u8]) -> Result<usize, Error> {
266 let mut i = 0;
267
268 for p in pages {
269 match (&p.signature, &p.raw) {
271 (None, None) => {
272 error!("cannot encode page without associated signature or private key");
273 continue;
274 }
275 _ => (),
276 };
277
278 let mut b = Base::from(p);
280 let n = b.encode(None, None, &mut buff[i..])?;
281
282 i += n;
283 }
284
285 Ok(i)
286 }
287}
288
289impl From<&Page> for Base {
290 fn from(page: &Page) -> Base {
291 let sig = page.signature().clone();
292
293 let mut default_options = vec![];
295
296 if let Some(issued) = page.issued {
297 default_options.push(Options::issued(issued));
298 }
299
300 if let Some(expiry) = page.expiry {
301 default_options.push(Options::expiry(expiry));
302 }
303
304 if let Some(prev_sig) = &page.previous_sig {
305 default_options.push(Options::prev_sig(prev_sig));
306 }
307
308 match &page.info {
310 PageInfo::Primary(primary) => {
311 default_options.push(Options::public_key(primary.pub_key.clone()));
312 }
313 PageInfo::Secondary(secondary) => {
314 default_options.push(Options::peer_id(secondary.peer_id.clone()));
315 }
316 PageInfo::Data(_data) => {}
317 }
318
319 let mut public_options = page.public_options.clone();
322 public_options.append(&mut default_options);
323
324 let mut b = Base::new(
326 page.id.clone(),
327 page.header.clone(),
328 page.body.clone(),
329 BaseOptions {
330 public_options,
331 private_options: page.private_options.clone(),
332 ..Default::default()
333 },
334 );
335
336 if let Some(sig) = sig {
337 b.set_signature(sig);
338 }
339
340 if let Some(raw) = &page.raw {
341 b.set_raw(raw.clone());
342 }
343
344 b.verified = page.verified;
345
346 b
347 }
348}
349
350impl TryFrom<Base> for Page {
351 type Error = Error;
352
353 fn try_from(base: Base) -> Result<Self, Error> {
354 let header = base.header();
355 let signature = base.signature();
356
357 let flags = header.flags();
358 let kind = header.kind();
359
360 if !kind.is_page() && !kind.is_data() {
361 return Err(Error::InvalidPageKind);
362 }
363
364 let (mut issued, mut expiry, mut previous_sig, mut peer_id) = (None, None, None, None);
365 let public_options = base
366 .public_options()
367 .iter()
368 .filter_map(|o| match &o {
369 Options::Issued(v) => {
370 issued = Some(v.when);
371 None
372 }
373 Options::Expiry(v) => {
374 expiry = Some(v.when);
375 None
376 }
377 Options::PrevSig(v) => {
378 previous_sig = Some(v.sig.clone());
379 None
380 }
381 Options::PeerId(v) => {
382 peer_id = Some(v.peer_id.clone());
383 None
384 }
385 _ => Some(o),
386 })
387 .map(|o| o.clone())
388 .collect();
389
390 let peer_id = base.peer_id.clone();
391
392 let _private_options = base.private_options();
394
395 let info = if kind.is_page() && !flags.contains(Flags::SECONDARY) {
396 let public_key: PublicKey = match &base.public_key {
400 Some(pk) => Ok(pk.clone()),
401 None => Err(Error::NoPublicKey),
402 }?;
403
404 let hash: Id = crypto::hash(&public_key).unwrap().into();
406 if &hash != base.id() {
407 return Err(Error::KeyIdMismatch);
408 }
409
410 PageInfo::primary(public_key)
411 } else if kind.is_page() && flags.contains(Flags::SECONDARY) {
412 let peer_id = match peer_id {
414 Some(id) => Ok(id),
415 None => Err(Error::NoPeerId),
416 }?;
417
418 PageInfo::secondary(peer_id)
419 } else if kind.is_data() {
420 PageInfo::Data(())
421 } else {
422 error!(
423 "Attempted to convert non-page base object ({:?}) to page",
424 kind
425 );
426 return Err(Error::UnexpectedPageType);
427 };
428
429 Ok(Page {
430 id: base.id().clone(),
431 header: header.clone(),
432 info,
433 body: base.body.clone(),
434 issued,
435 expiry,
436
437 previous_sig,
438
439 public_options,
440 private_options: base.private_options.clone(),
441 signature: signature.clone(),
442 verified: base.verified,
443
444 raw: base.raw().clone(),
445 _extend: (),
446 })
447 }
448}