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}