1use crate::util::Iterable;
2use crate::{
3 entity::Entity,
4 error::ValidationError,
5 node::{ContextData, Node, NodeInner},
6 property::PropertyError,
7 proto::{self},
8 storage::StorageEngine,
9};
10use ankql::{ast::Predicate, error::ParseError};
11use ankurah_proto::Attested;
12use async_trait::async_trait;
13use thiserror::Error;
14use tracing::debug;
15#[derive(Debug, Error)]
17pub enum AccessDenied {
18 #[error("Access denied by policy: {0}")]
19 ByPolicy(&'static str),
20 #[error("Access denied by collection: {0}")]
21 CollectionDenied(proto::CollectionId),
22 #[error("Access denied by property error: {0}")]
23 PropertyError(Box<PropertyError>),
24 #[error("Access denied by parse error: {0}")]
25 ParseError(ParseError),
26 #[error("Insufficient attestation")]
27 InsufficientAttestation,
28}
29
30impl From<PropertyError> for AccessDenied {
31 fn from(error: PropertyError) -> Self { AccessDenied::PropertyError(Box::new(error)) }
32}
33impl From<ParseError> for AccessDenied {
34 fn from(error: ParseError) -> Self { AccessDenied::ParseError(error) }
35}
36
37#[cfg(feature = "wasm")]
38impl From<AccessDenied> for wasm_bindgen::JsValue {
39 fn from(error: AccessDenied) -> Self { wasm_bindgen::JsValue::from_str(&error.to_string()) }
40}
41
42impl AccessDenied {}
43
44#[async_trait]
50pub trait PolicyAgent: Clone + Send + Sync + 'static {
51 type ContextData: ContextData;
54
55 fn sign_request<SE: StorageEngine, C>(
58 &self,
59 node: &NodeInner<SE, Self>,
60 cdata: &C,
61 request: &proto::NodeRequest,
62 ) -> Result<Vec<proto::AuthData>, AccessDenied>
63 where
64 C: Iterable<Self::ContextData>;
65
66 async fn check_request<SE: StorageEngine, A>(
71 &self,
72 node: &Node<SE, Self>,
73 auth: &A,
74 request: &proto::NodeRequest,
75 ) -> Result<Vec<Self::ContextData>, ValidationError>
76 where
77 Self: Sized,
78 A: Iterable<proto::AuthData> + Send + Sync;
79
80 fn check_event<SE: StorageEngine>(
86 &self,
87 node: &Node<SE, Self>,
88 cdata: &Self::ContextData,
89 entity_before: &Entity,
90 entity_after: &Entity,
91 event: &proto::Event,
92 ) -> Result<Option<proto::Attestation>, AccessDenied>;
93
94 fn validate_received_event<SE: StorageEngine>(
97 &self,
98 node: &Node<SE, Self>,
99 received_from_node: &proto::EntityId,
100 event: &Attested<proto::Event>,
101 ) -> Result<(), AccessDenied>;
102
103 fn attest_state<SE: StorageEngine>(&self, node: &Node<SE, Self>, state: &proto::EntityState) -> Option<proto::Attestation>;
105
106 fn validate_received_state<SE: StorageEngine>(
107 &self,
108 node: &Node<SE, Self>,
109 received_from_node: &proto::EntityId,
110 state: &Attested<proto::EntityState>,
111 ) -> Result<(), AccessDenied>;
112
113 fn can_access_collection<C>(&self, data: &C, collection: &proto::CollectionId) -> Result<(), AccessDenied>
115 where C: Iterable<Self::ContextData>;
116
117 fn filter_predicate<C>(&self, data: &C, collection: &proto::CollectionId, predicate: Predicate) -> Result<Predicate, AccessDenied>
119 where C: Iterable<Self::ContextData>;
120
121 fn check_read<C>(
126 &self,
127 data: &C,
128 id: &proto::EntityId,
129 collection: &proto::CollectionId,
130 state: &proto::State,
131 ) -> Result<(), AccessDenied>
132 where
133 C: Iterable<Self::ContextData>;
134
135 fn check_read_event<C>(&self, data: &C, event: &Attested<proto::Event>) -> Result<(), AccessDenied>
137 where C: Iterable<Self::ContextData>;
138
139 fn check_write(&self, data: &Self::ContextData, entity: &Entity, event: Option<&proto::Event>) -> Result<(), AccessDenied>;
141
142 fn validate_causal_assertion<SE: StorageEngine>(
145 &self,
146 node: &Node<SE, Self>,
147 peer_id: &proto::EntityId,
148 head_relation: &proto::CausalAssertion,
149 ) -> Result<(), AccessDenied>;
150
151 }
159
160#[derive(Clone)]
162pub struct PermissiveAgent {}
163
164impl Default for PermissiveAgent {
165 fn default() -> Self { Self::new() }
166}
167
168impl PermissiveAgent {
169 pub fn new() -> Self { Self {} }
170}
171
172#[async_trait]
173impl PolicyAgent for PermissiveAgent {
174 type ContextData = &'static DefaultContext;
175
176 fn sign_request<SE: StorageEngine, C>(
178 &self,
179 _node: &NodeInner<SE, Self>,
180 cdata: &C,
181 _request: &proto::NodeRequest,
182 ) -> Result<Vec<proto::AuthData>, AccessDenied>
183 where
184 C: Iterable<Self::ContextData>,
185 {
186 debug!("PermissiveAgent sign_request: {:?}", _request);
187 Ok(cdata.iterable().map(|_| proto::AuthData(vec![])).collect())
189 }
190
191 async fn check_request<SE: StorageEngine, A>(
193 &self,
194 _node: &Node<SE, Self>,
195 auth: &A,
196 _request: &proto::NodeRequest,
197 ) -> Result<Vec<Self::ContextData>, ValidationError>
198 where
199 A: Iterable<proto::AuthData> + Send + Sync,
200 {
201 Ok(auth.iterable().map(|_| DEFAULT_CONTEXT).collect())
203 }
204
205 fn check_event<SE: StorageEngine>(
207 &self,
208 _node: &Node<SE, Self>,
209 _cdata: &Self::ContextData,
210 _entity_before: &Entity,
211 _entity_after: &Entity,
212 _event: &proto::Event,
213 ) -> Result<Option<proto::Attestation>, AccessDenied> {
214 Ok(None)
215 }
216
217 fn validate_received_event<SE: StorageEngine>(
218 &self,
219 _node: &Node<SE, Self>,
220 _from_node: &proto::EntityId,
221 _event: &proto::Attested<proto::Event>,
222 ) -> Result<(), AccessDenied> {
223 Ok(())
224 }
225
226 fn attest_state<SE: StorageEngine>(&self, _node: &Node<SE, Self>, _state: &proto::EntityState) -> Option<proto::Attestation> {
227 None
230 }
231
232 fn validate_received_state<SE: StorageEngine>(
233 &self,
234 _node: &Node<SE, Self>,
235 _from_node: &proto::EntityId,
236 _state: &Attested<proto::EntityState>,
237 ) -> Result<(), AccessDenied> {
238 Ok(())
241 }
242
243 fn can_access_collection<C>(&self, _data: &C, _collection: &proto::CollectionId) -> Result<(), AccessDenied>
244 where C: Iterable<Self::ContextData> {
245 Ok(())
247 }
248
249 fn check_read<C>(
250 &self,
251 _data: &C,
252 _id: &proto::EntityId,
253 _collection: &proto::CollectionId,
254 _state: &proto::State,
255 ) -> Result<(), AccessDenied>
256 where
257 C: Iterable<Self::ContextData>,
258 {
259 Ok(())
261 }
262
263 fn check_read_event<C>(&self, _data: &C, _event: &Attested<proto::Event>) -> Result<(), AccessDenied>
264 where C: Iterable<Self::ContextData> {
265 Ok(())
267 }
268
269 fn check_write(&self, _context: &Self::ContextData, _entity: &Entity, _event: Option<&proto::Event>) -> Result<(), AccessDenied> {
270 Ok(())
271 }
272
273 fn validate_causal_assertion<SE: StorageEngine>(
274 &self,
275 _node: &Node<SE, Self>,
276 _peer_id: &proto::EntityId,
277 _head_relation: &proto::CausalAssertion,
278 ) -> Result<(), AccessDenied> {
279 Ok(())
281 }
282
283 fn filter_predicate<C>(&self, _data: &C, _collection: &proto::CollectionId, predicate: Predicate) -> Result<Predicate, AccessDenied>
284 where C: Iterable<Self::ContextData> {
285 Ok(predicate)
287 }
288
289 }
301
302#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
305pub struct DefaultContext {}
306pub static DEFAULT_CONTEXT: &DefaultContext = &DefaultContext {};
307
308impl Default for DefaultContext {
309 fn default() -> Self { Self::new() }
310}
311
312impl DefaultContext {
313 pub fn new() -> Self { Self {} }
314}
315
316#[async_trait]
317impl ContextData for &'static DefaultContext {}