1use crate::util::Iterable;
2use crate::{
3 entity::Entity,
4 error::ValidationError,
5 node::{ContextData, Node, NodeInner, WeakNode},
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 on_node_ready<SE: StorageEngine + Send + Sync + 'static>(&self, _node: WeakNode<SE, Self>) {}
58
59 fn sign_request<SE: StorageEngine, C>(
62 &self,
63 node: &NodeInner<SE, Self>,
64 cdata: &C,
65 request: &proto::NodeRequest,
66 ) -> Result<Vec<proto::AuthData>, AccessDenied>
67 where
68 C: Iterable<Self::ContextData>;
69
70 async fn check_request<SE: StorageEngine, A>(
75 &self,
76 node: &Node<SE, Self>,
77 auth: &A,
78 request: &proto::NodeRequest,
79 ) -> Result<Vec<Self::ContextData>, ValidationError>
80 where
81 Self: Sized,
82 A: Iterable<proto::AuthData> + Send + Sync;
83
84 fn check_event<SE: StorageEngine>(
90 &self,
91 node: &Node<SE, Self>,
92 cdata: &Self::ContextData,
93 entity_before: &Entity,
94 entity_after: &Entity,
95 event: &proto::Event,
96 ) -> Result<Option<proto::Attestation>, AccessDenied>;
97
98 fn validate_received_event<SE: StorageEngine>(
101 &self,
102 node: &Node<SE, Self>,
103 received_from_node: &proto::EntityId,
104 event: &Attested<proto::Event>,
105 ) -> Result<(), AccessDenied>;
106
107 fn attest_state<SE: StorageEngine>(&self, node: &Node<SE, Self>, state: &proto::EntityState) -> Option<proto::Attestation>;
109
110 fn validate_received_state<SE: StorageEngine>(
111 &self,
112 node: &Node<SE, Self>,
113 received_from_node: &proto::EntityId,
114 state: &Attested<proto::EntityState>,
115 ) -> Result<(), AccessDenied>;
116
117 fn can_access_collection<C>(&self, data: &C, collection: &proto::CollectionId) -> Result<(), AccessDenied>
119 where C: Iterable<Self::ContextData>;
120
121 fn filter_predicate<C>(&self, data: &C, collection: &proto::CollectionId, predicate: Predicate) -> Result<Predicate, AccessDenied>
123 where C: Iterable<Self::ContextData>;
124
125 fn check_read<C>(
130 &self,
131 data: &C,
132 id: &proto::EntityId,
133 collection: &proto::CollectionId,
134 state: &proto::State,
135 ) -> Result<(), AccessDenied>
136 where
137 C: Iterable<Self::ContextData>;
138
139 fn check_read_event<C>(&self, data: &C, event: &Attested<proto::Event>) -> Result<(), AccessDenied>
141 where C: Iterable<Self::ContextData>;
142
143 fn check_write(&self, data: &Self::ContextData, entity: &Entity, event: Option<&proto::Event>) -> Result<(), AccessDenied>;
145
146 fn validate_causal_assertion<SE: StorageEngine>(
149 &self,
150 node: &Node<SE, Self>,
151 peer_id: &proto::EntityId,
152 head_relation: &proto::CausalAssertion,
153 ) -> Result<(), AccessDenied>;
154
155 }
163
164#[derive(Clone)]
166pub struct PermissiveAgent {}
167
168impl Default for PermissiveAgent {
169 fn default() -> Self { Self::new() }
170}
171
172impl PermissiveAgent {
173 pub fn new() -> Self { Self {} }
174}
175
176#[async_trait]
177impl PolicyAgent for PermissiveAgent {
178 type ContextData = &'static DefaultContext;
179
180 fn sign_request<SE: StorageEngine, C>(
182 &self,
183 _node: &NodeInner<SE, Self>,
184 cdata: &C,
185 _request: &proto::NodeRequest,
186 ) -> Result<Vec<proto::AuthData>, AccessDenied>
187 where
188 C: Iterable<Self::ContextData>,
189 {
190 debug!("PermissiveAgent sign_request: {:?}", _request);
191 Ok(cdata.iterable().map(|_| proto::AuthData(vec![])).collect())
193 }
194
195 async fn check_request<SE: StorageEngine, A>(
197 &self,
198 _node: &Node<SE, Self>,
199 auth: &A,
200 _request: &proto::NodeRequest,
201 ) -> Result<Vec<Self::ContextData>, ValidationError>
202 where
203 A: Iterable<proto::AuthData> + Send + Sync,
204 {
205 Ok(auth.iterable().map(|_| DEFAULT_CONTEXT).collect())
207 }
208
209 fn check_event<SE: StorageEngine>(
211 &self,
212 _node: &Node<SE, Self>,
213 _cdata: &Self::ContextData,
214 _entity_before: &Entity,
215 _entity_after: &Entity,
216 _event: &proto::Event,
217 ) -> Result<Option<proto::Attestation>, AccessDenied> {
218 Ok(None)
219 }
220
221 fn validate_received_event<SE: StorageEngine>(
222 &self,
223 _node: &Node<SE, Self>,
224 _from_node: &proto::EntityId,
225 _event: &proto::Attested<proto::Event>,
226 ) -> Result<(), AccessDenied> {
227 Ok(())
228 }
229
230 fn attest_state<SE: StorageEngine>(&self, _node: &Node<SE, Self>, _state: &proto::EntityState) -> Option<proto::Attestation> {
231 None
234 }
235
236 fn validate_received_state<SE: StorageEngine>(
237 &self,
238 _node: &Node<SE, Self>,
239 _from_node: &proto::EntityId,
240 _state: &Attested<proto::EntityState>,
241 ) -> Result<(), AccessDenied> {
242 Ok(())
245 }
246
247 fn can_access_collection<C>(&self, _data: &C, _collection: &proto::CollectionId) -> Result<(), AccessDenied>
248 where C: Iterable<Self::ContextData> {
249 Ok(())
251 }
252
253 fn check_read<C>(
254 &self,
255 _data: &C,
256 _id: &proto::EntityId,
257 _collection: &proto::CollectionId,
258 _state: &proto::State,
259 ) -> Result<(), AccessDenied>
260 where
261 C: Iterable<Self::ContextData>,
262 {
263 Ok(())
265 }
266
267 fn check_read_event<C>(&self, _data: &C, _event: &Attested<proto::Event>) -> Result<(), AccessDenied>
268 where C: Iterable<Self::ContextData> {
269 Ok(())
271 }
272
273 fn check_write(&self, _context: &Self::ContextData, _entity: &Entity, _event: Option<&proto::Event>) -> Result<(), AccessDenied> {
274 Ok(())
275 }
276
277 fn validate_causal_assertion<SE: StorageEngine>(
278 &self,
279 _node: &Node<SE, Self>,
280 _peer_id: &proto::EntityId,
281 _head_relation: &proto::CausalAssertion,
282 ) -> Result<(), AccessDenied> {
283 Ok(())
285 }
286
287 fn filter_predicate<C>(&self, _data: &C, _collection: &proto::CollectionId, predicate: Predicate) -> Result<Predicate, AccessDenied>
288 where C: Iterable<Self::ContextData> {
289 Ok(predicate)
291 }
292
293 }
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
309pub struct DefaultContext {}
310pub static DEFAULT_CONTEXT: &DefaultContext = &DefaultContext {};
311
312impl Default for DefaultContext {
313 fn default() -> Self { Self::new() }
314}
315
316impl DefaultContext {
317 pub fn new() -> Self { Self {} }
318}
319
320#[async_trait]
321impl ContextData for &'static DefaultContext {}