dsf_core/service/
subscriber.rs1use core::convert::TryInto;
2
3#[cfg(feature = "alloc")]
4use alloc::prelude::v1::*;
5
6use crate::crypto;
7use crate::error::Error;
8use crate::page::{Page, PageInfo};
9use crate::service::Service;
10use crate::types::*;
11
12pub trait Subscriber {
13 fn load(page: &Page) -> Result<Service, Error>;
15
16 fn apply_primary(&mut self, primary: &Page) -> Result<bool, Error>;
18
19 fn validate_page(&mut self, page: &Page) -> Result<(), Error>;
21}
22
23impl Subscriber for Service {
24 fn load(page: &Page) -> Result<Service, Error> {
26 let header = page.header();
27 let flags = header.flags();
28
29 let public_key = match page.info() {
30 PageInfo::Primary(primary) => primary.pub_key.clone(),
31 _ => {
32 error!("Attempted to load service from secondary page");
33 return Err(Error::UnexpectedPageType);
34 }
35 };
36
37 let body = page.body();
38
39 let public_options = page.public_options();
40 let private_options = page.private_options();
41
42 Ok(Service {
43 id: page.id().clone(),
44
45 application_id: header.application_id(),
46 kind: header.kind().try_into().unwrap(),
47
48 version: header.index(),
49 data_index: 0,
50
51 body: body.clone(),
52
53 public_options: public_options.to_vec(),
54 private_options: private_options.clone(),
55
56 public_key,
57 private_key: None,
58
59 encrypted: flags.contains(Flags::ENCRYPTED),
60 secret_key: None,
61
62 last_sig: page.signature(),
63 })
64 }
65
66 fn apply_primary(&mut self, update: &Page) -> Result<bool, Error> {
69 let header = update.header();
70
71 let flags = header.flags();
72 let body = update.body();
73
74 let public_options = update.public_options();
75 let private_options = update.private_options();
76
77 self.validate_primary(update)?;
78
79 if header.index() == self.version {
80 return Ok(false);
81 }
82 if header.index() <= self.version {
83 return Err(Error::InvalidServiceVersion);
84 }
85
86 self.version = header.index();
87 self.encrypted = flags.contains(Flags::ENCRYPTED);
88 self.body = body.clone();
89 self.public_options = public_options.to_vec();
90 self.private_options = private_options.clone();
91
92 Ok(true)
93 }
94
95 fn validate_page(&mut self, page: &Page) -> Result<(), Error> {
96 let header = page.header();
97
98 if header.kind().is_page() {
99 if !header.flags().contains(Flags::SECONDARY) {
100 self.validate_primary(page)
101 } else {
102 self.validate_secondary(page)
103 }
104 } else if header.kind().is_data() {
105 self.validate_data(page)
106 } else {
107 Err(Error::UnexpectedPageKind)
108 }
109 }
110}
111
112impl Service {
113 pub(crate) fn validate_primary(&mut self, page: &Page) -> Result<(), Error> {
115 let header = page.header();
116
117 if !header.kind().is_page() {
118 return Err(Error::ExpectedPrimaryPage);
119 }
120 if header.flags().contains(Flags::SECONDARY) {
121 return Err(Error::ExpectedPrimaryPage);
122 }
123
124 if page.id() != &self.id {
125 return Err(Error::UnexpectedServiceId);
126 }
127 if header.application_id() != self.application_id {
128 return Err(Error::UnexpectedApplicationId);
129 }
130 if header.kind() != self.kind.into() {
131 return Err(Error::InvalidPageKind);
132 }
133
134 let public_key: PublicKey = match page.info() {
136 PageInfo::Primary(primary) => primary.pub_key.clone(),
137 _ => {
138 error!("Attempted to update service from secondary page");
139 return Err(Error::ExpectedPrimaryPage);
140 }
141 };
142
143 if self.id != crypto::hash(&public_key).unwrap() {
145 return Err(Error::KeyIdMismatch);
146 }
147
148 if self.public_key != public_key {
150 return Err(Error::PublicKeyChanged);
151 }
152
153 Ok(())
154 }
155
156 pub(crate) fn validate_secondary(&mut self, secondary: &Page) -> Result<(), Error> {
158 let header = secondary.header();
159
160 if !header.kind().is_page() {
161 return Err(Error::ExpectedPrimaryPage);
162 }
163 if !header.flags().contains(Flags::SECONDARY) {
164 return Err(Error::ExpectedSecondaryPage);
165 }
166
167 let publisher_id = match secondary.info().peer_id() {
168 Some(p) => p,
169 None => return Err(Error::NoPeerId),
170 };
171 if publisher_id != self.id {
172 return Err(Error::UnexpectedPeerId);
173 }
174
175 if header.application_id() != self.application_id {
176 return Err(Error::UnexpectedApplicationId);
177 }
178
179 Ok(())
180 }
181
182 pub(crate) fn validate_data(&mut self, data: &Page) -> Result<(), Error> {
184 let header = data.header();
185
186 if !header.kind().is_data() {
187 return Err(Error::ExpectedDataObject);
188 }
189
190 if data.id() != &self.id {
191 return Err(Error::UnexpectedServiceId);
192 }
193 if header.application_id() != self.application_id {
194 return Err(Error::UnexpectedApplicationId);
195 }
196
197 Ok(())
198 }
199}