1use super::{
15 AccessAction, AccessDecisionError, AccessResource, AdmittedLysPass, DeliberateDecision,
16 GrantReceipt, HotAction, LysDeliberateConsumer, LysPassConsumer, SubjectBinding,
17 admit_lys_pass, decide_deliberate, decide_message,
18};
19use crate::link::LinkAction;
20use std::sync::Arc;
21
22impl SubjectBinding {
23 pub fn link(
28 network_id: String,
29 link_id: String,
30 subject: String,
31 ) -> Result<Self, super::SubjectBindingError> {
32 let mut binding = Self::new(network_id, link_id, subject)?;
33 binding.resource.kind = super::ResourceKind::Link;
34 Ok(binding)
35 }
36}
37
38#[derive(Debug)]
40pub struct LysAdmissionRefusal {
41 pub reason: String,
43}
44
45impl std::fmt::Display for LysAdmissionRefusal {
46 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(formatter, "lys pass admission refused: {}", self.reason)
48 }
49}
50
51impl std::error::Error for LysAdmissionRefusal {}
52
53pub trait LysAdmitter: Send + Sync + std::fmt::Debug {
55 fn admit(&self, pass: &[u8], now: u64) -> Result<Box<dyn LysSession>, LysAdmissionRefusal>;
61}
62
63pub trait LysSession: Send + Sync + std::fmt::Debug {
65 fn hold_permission(
70 &self,
71 _request: super::prepared::PermissionRequest<'_>,
72 ) -> Result<serde_json::Value, lys_pass::Error> {
73 Err(lys_pass::Error::CannotAsk(
74 "prepared permission unavailable",
75 ))
76 }
77
78 fn hold_site(
83 &self,
84 _request: super::prepared::SiteRequest<'_>,
85 ) -> Result<serde_json::Value, lys_pass::Error> {
86 Err(lys_pass::Error::CannotAsk(
87 "prepared construction unavailable",
88 ))
89 }
90
91 fn holder(&self) -> &str;
93
94 fn holder_kind(&self) -> Option<&str> {
98 None
99 }
100
101 fn issued_at(&self) -> Option<u64> {
104 None
105 }
106
107 fn decide(
112 &self,
113 subject: &SubjectBinding,
114 action: HotAction,
115 now: u64,
116 ) -> Result<GrantReceipt, AccessDecisionError>;
117
118 fn decide_link(
124 &self,
125 subject: &SubjectBinding,
126 action: LinkAction,
127 now: u64,
128 ) -> Result<GrantReceipt, AccessDecisionError>;
129
130 fn open_link(
137 &self,
138 link: &AccessResource,
139 end: LinkAction,
140 now: u64,
141 ) -> Result<DeliberateDecision, AccessDecisionError>;
142
143 fn decide_live(
152 &self,
153 resource: &AccessResource,
154 action: AccessAction,
155 now: u64,
156 ) -> Result<DeliberateDecision, AccessDecisionError>;
157}
158
159#[derive(Debug)]
161pub struct ConsumerAdmitter<C> {
162 consumer: Arc<C>,
163}
164
165impl<C> ConsumerAdmitter<C> {
166 #[must_use]
168 pub const fn new(consumer: Arc<C>) -> Self {
169 Self { consumer }
170 }
171}
172
173struct ConsumerSession<C: LysPassConsumer> {
174 consumer: Arc<C>,
175 pass: AdmittedLysPass<C::Pass>,
176 holder: String,
177 holder_kind: Option<String>,
180}
181
182impl<C: LysPassConsumer> std::fmt::Debug for ConsumerSession<C> {
183 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 formatter
185 .debug_struct("ConsumerSession")
186 .field("holder", &self.holder)
187 .finish_non_exhaustive()
188 }
189}
190
191impl<C> LysAdmitter for ConsumerAdmitter<C>
192where
193 C: LysDeliberateConsumer + Send + Sync + std::fmt::Debug + 'static,
194 C::Pass: Send + Sync + 'static,
195 C::Holder: AsRef<str>,
196{
197 fn admit(&self, pass: &[u8], now: u64) -> Result<Box<dyn LysSession>, LysAdmissionRefusal> {
198 let admitted = admit_lys_pass(self.consumer.as_ref(), pass, now).map_err(|error| {
199 LysAdmissionRefusal {
200 reason: error.to_string(),
201 }
202 })?;
203 let holder = self
204 .consumer
205 .verified_holder(&admitted.pass)
206 .as_ref()
207 .to_owned();
208 let holder_kind = self
209 .consumer
210 .verified_holder_kind(&admitted.pass)
211 .map(str::to_owned);
212 Ok(Box::new(ConsumerSession {
213 consumer: Arc::clone(&self.consumer),
214 pass: admitted,
215 holder,
216 holder_kind,
217 }))
218 }
219}
220
221impl<C> LysSession for ConsumerSession<C>
222where
223 C: LysDeliberateConsumer + Send + Sync + 'static,
224 C::Pass: Send + Sync + 'static,
225{
226 fn hold_permission(
227 &self,
228 request: super::prepared::PermissionRequest<'_>,
229 ) -> Result<serde_json::Value, lys_pass::Error> {
230 self.consumer.hold_permission(&self.pass.pass, request)
231 }
232 fn hold_site(
233 &self,
234 request: super::prepared::SiteRequest<'_>,
235 ) -> Result<serde_json::Value, lys_pass::Error> {
236 self.consumer.hold_site(&self.pass.pass, request)
237 }
238 fn holder(&self) -> &str {
239 &self.holder
240 }
241
242 fn holder_kind(&self) -> Option<&str> {
243 self.holder_kind.as_deref()
244 }
245
246 fn issued_at(&self) -> Option<u64> {
247 self.consumer.verified_issued_at(&self.pass.pass)
248 }
249
250 fn decide(
251 &self,
252 subject: &SubjectBinding,
253 action: HotAction,
254 now: u64,
255 ) -> Result<GrantReceipt, AccessDecisionError> {
256 decide_message(self.consumer.as_ref(), &self.pass, subject, action, now)
257 }
258
259 fn decide_link(
260 &self,
261 subject: &SubjectBinding,
262 action: LinkAction,
263 now: u64,
264 ) -> Result<GrantReceipt, AccessDecisionError> {
265 self.consumer
266 .decide_link(&self.pass.pass, subject, action, now)
267 }
268
269 fn open_link(
270 &self,
271 link: &AccessResource,
272 end: LinkAction,
273 now: u64,
274 ) -> Result<DeliberateDecision, AccessDecisionError> {
275 self.decide_live(link, end.access_action(), now)
276 }
277
278 fn decide_live(
279 &self,
280 resource: &AccessResource,
281 action: AccessAction,
282 now: u64,
283 ) -> Result<DeliberateDecision, AccessDecisionError> {
284 decide_deliberate(self.consumer.as_ref(), &self.pass, resource, action, now)
285 }
286}