Skip to main content

bc_xid/
service.rs

1use std::collections::HashSet;
2
3use bc_components::{
4    PublicKeysProvider, Reference, ReferenceProvider, URI, XIDProvider,
5};
6use bc_envelope::{
7    Envelope, EnvelopeEncodable,
8    extension::{
9        ALLOW_RAW, CAPABILITY, CAPABILITY_RAW, DELEGATE, DELEGATE_RAW, KEY,
10        KEY_RAW, NAME, NAME_RAW,
11    },
12};
13
14use crate::{Error, HasPermissions, Permissions, Privilege, Result};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Service {
18    uri: URI,
19    key_references: HashSet<Reference>,
20    delegate_references: HashSet<Reference>,
21    permissions: Permissions,
22    capability: String,
23    name: String,
24}
25
26impl std::hash::Hash for Service {
27    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
28        self.uri.hash(state);
29    }
30}
31
32impl Service {
33    pub fn new(uri: impl AsRef<URI>) -> Self {
34        Self {
35            uri: uri.as_ref().clone(),
36            key_references: HashSet::new(),
37            delegate_references: HashSet::new(),
38            permissions: Permissions::new(),
39            capability: String::new(),
40            name: String::new(),
41        }
42    }
43
44    pub fn uri(&self) -> &URI { &self.uri }
45
46    pub fn capability(&self) -> &str { &self.capability }
47
48    pub fn set_capability(&mut self, capability: impl Into<String>) {
49        self.capability = capability.into();
50    }
51
52    pub fn add_capability(&mut self, capability: &str) -> Result<()> {
53        if !self.capability.is_empty() {
54            return Err(Error::Duplicate { item: "capability".to_string() });
55        }
56        if capability.is_empty() {
57            return Err(Error::EmptyValue { field: "capability".to_string() });
58        }
59        self.set_capability(capability);
60
61        Ok(())
62    }
63
64    pub fn key_references(&self) -> &HashSet<Reference> { &self.key_references }
65
66    pub fn key_referenecs_mut(&mut self) -> &mut HashSet<Reference> {
67        &mut self.key_references
68    }
69
70    pub fn add_key_reference(
71        &mut self,
72        key_reference: impl AsRef<Reference>,
73    ) -> Result<()> {
74        if !self.key_references.contains(key_reference.as_ref()) {
75            self.key_references.insert(*key_reference.as_ref());
76        } else {
77            return Err(Error::Duplicate { item: "key reference".to_string() });
78        }
79
80        Ok(())
81    }
82
83    pub fn add_key(&mut self, key: &dyn PublicKeysProvider) -> Result<()> {
84        self.add_key_reference(key.public_keys().reference())
85    }
86
87    pub fn delegate_references(&self) -> &HashSet<Reference> {
88        &self.delegate_references
89    }
90
91    pub fn delegate_references_mut(&mut self) -> &mut HashSet<Reference> {
92        &mut self.delegate_references
93    }
94
95    pub fn add_delegate_reference(
96        &mut self,
97        delegate_reference: impl AsRef<Reference>,
98    ) -> Result<()> {
99        if !self
100            .delegate_references
101            .contains(delegate_reference.as_ref())
102        {
103            self.delegate_references
104                .insert(*delegate_reference.as_ref());
105        } else {
106            return Err(Error::Duplicate {
107                item: "delegate reference".to_string(),
108            });
109        }
110
111        Ok(())
112    }
113
114    pub fn add_delegate(&mut self, delegate: &dyn XIDProvider) -> Result<()> {
115        self.add_delegate_reference(delegate.xid().reference())
116    }
117
118    pub fn name(&self) -> &str { &self.name }
119
120    pub fn set_name(&mut self, name: impl Into<String>) -> Result<()> {
121        if !self.name.is_empty() {
122            return Err(Error::Duplicate { item: "name".to_string() });
123        }
124        let name = name.into();
125        if name.is_empty() {
126            return Err(Error::EmptyValue { field: "name".to_string() });
127        }
128        self.name = name;
129        Ok(())
130    }
131}
132
133impl HasPermissions for Service {
134    fn permissions(&self) -> &Permissions { &self.permissions }
135
136    fn permissions_mut(&mut self) -> &mut Permissions { &mut self.permissions }
137}
138
139impl EnvelopeEncodable for Service {
140    fn into_envelope(self) -> bc_envelope::Envelope {
141        let mut envelope = Envelope::new(self.uri);
142
143        envelope = self
144            .key_references
145            .iter()
146            .cloned()
147            .fold(envelope, |envelope, key| envelope.add_assertion(KEY, key));
148
149        envelope = self
150            .delegate_references
151            .iter()
152            .cloned()
153            .fold(envelope, |envelope, delegate| {
154                envelope.add_assertion(DELEGATE, delegate)
155            });
156
157        envelope =
158            envelope.add_nonempty_string_assertion(CAPABILITY, self.capability);
159        envelope = envelope.add_nonempty_string_assertion(NAME, self.name);
160        self.permissions.add_to_envelope(envelope)
161    }
162}
163
164impl TryFrom<Envelope> for Service {
165    type Error = Error;
166
167    fn try_from(envelope: Envelope) -> Result<Self> {
168        Self::try_from(&envelope)
169    }
170}
171
172impl TryFrom<&Envelope> for Service {
173    type Error = Error;
174
175    fn try_from(envelope: &Envelope) -> Result<Self> {
176        let uri: URI = envelope.subject().try_leaf()?.try_into()?;
177
178        let mut service = Service::new(uri);
179
180        for assertion in envelope.assertions() {
181            let predicate =
182                assertion.try_predicate()?.try_known_value()?.value();
183            let object = assertion.try_object()?;
184            if object.has_assertions() {
185                return Err(Error::UnexpectedNestedAssertions);
186            }
187            match predicate {
188                KEY_RAW => {
189                    let key = Reference::try_from(object.try_leaf()?)?;
190                    service.add_key_reference(key)?;
191                }
192                DELEGATE_RAW => {
193                    let delegate = Reference::try_from(object.try_leaf()?)?;
194                    service.add_delegate_reference(delegate)?;
195                }
196                CAPABILITY_RAW => {
197                    let capability = object.try_leaf()?.try_into_text()?;
198                    service.add_capability(&capability)?;
199                }
200                NAME_RAW => {
201                    let name = object.try_leaf()?.try_into_text()?;
202                    service.set_name(&name)?;
203                }
204                ALLOW_RAW => {
205                    service.add_allow(Privilege::try_from(object)?);
206                }
207                _ => {
208                    return Err(Error::UnexpectedPredicate {
209                        predicate: predicate.to_string(),
210                    });
211                }
212            }
213        }
214
215        Ok(service)
216    }
217}