guardian_db/access_controller/
manifest.rs

1use crate::error::{GuardianError, Result};
2use crate::ipfs_core_api::client::IpfsClient;
3use cid::Cid;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::sync::{Arc, Mutex};
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
9pub struct Manifest {
10    /// O tipo do controlador de acesso (ex: "ipfs", "GuardianDB").
11    #[serde(rename = "type")]
12    pub get_type: String,
13
14    /// Os parâmetros de configuração para este controlador de acesso.
15    #[serde(rename = "params")]
16    pub params: CreateAccessControllerOptions,
17}
18
19/// Contém as opções de configuração para um controlador de acesso.
20#[derive(Debug, Clone)]
21pub struct CreateAccessControllerOptions {
22    pub skip_manifest: bool,
23    pub address: Cid,
24    pub get_type: String,
25    pub name: String,
26    access: Arc<Mutex<HashMap<String, Vec<String>>>>,
27}
28
29// Implementação manual de Serialize para sincronizar dados antes da serialização
30impl Serialize for CreateAccessControllerOptions {
31    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
32    where
33        S: serde::Serializer,
34    {
35        use serde::ser::SerializeStruct;
36        let mut state = serializer.serialize_struct("CreateAccessControllerOptions", 5)?;
37        state.serialize_field("skip_manifest", &self.skip_manifest)?;
38        state.serialize_field("address", &self.address)?; // CID serializa nativamente  
39        state.serialize_field("type", &self.get_type)?;
40        state.serialize_field("name", &self.name)?;
41        // Serializa os dados de acesso diretamente do Mutex
42        if let Ok(access_guard) = self.access.lock()
43            && !access_guard.is_empty()
44        {
45            state.serialize_field("access", &*access_guard)?;
46        }
47        state.end()
48    }
49}
50
51// Implementação manual de Deserialize para sincronizar dados após a deserialização
52impl<'de> Deserialize<'de> for CreateAccessControllerOptions {
53    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
54    where
55        D: serde::Deserializer<'de>,
56    {
57        use serde::de::{MapAccess, Visitor};
58        use std::fmt;
59        struct OptionsVisitor;
60        impl<'de> Visitor<'de> for OptionsVisitor {
61            type Value = CreateAccessControllerOptions;
62            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
63                formatter.write_str("struct CreateAccessControllerOptions")
64            }
65            fn visit_map<V>(
66                self,
67                mut map: V,
68            ) -> std::result::Result<CreateAccessControllerOptions, V::Error>
69            where
70                V: MapAccess<'de>,
71            {
72                let mut skip_manifest = false;
73                let mut address = Cid::default();
74                let mut type_field = String::new();
75                let mut name = String::new();
76                let mut access = HashMap::new();
77
78                while let Some(key) = map.next_key::<String>()? {
79                    match key.as_str() {
80                        "skip_manifest" => skip_manifest = map.next_value()?,
81                        "address" => {
82                            address = map.next_value()?; // CID deserializa nativamente
83                        }
84                        "type" => type_field = map.next_value()?,
85                        "name" => name = map.next_value()?,
86                        "access" => access = map.next_value()?,
87                        _ => {
88                            let _ = map.next_value::<serde::de::IgnoredAny>()?;
89                        }
90                    }
91                }
92                Ok(CreateAccessControllerOptions {
93                    skip_manifest,
94                    address,
95                    get_type: type_field,
96                    name,
97                    access: Arc::new(Mutex::new(access)),
98                })
99            }
100        }
101
102        deserializer.deserialize_struct(
103            "CreateAccessControllerOptions",
104            &["skip_manifest", "address", "type", "name", "access"],
105            OptionsVisitor,
106        )
107    }
108}
109
110impl Default for CreateAccessControllerOptions {
111    fn default() -> Self {
112        Self {
113            skip_manifest: false,
114            address: Cid::default(),
115            get_type: String::new(),
116            name: String::new(),
117            access: Arc::new(Mutex::new(HashMap::new())),
118        }
119    }
120}
121
122/// Define a interface para os parâmetros de um manifesto.
123pub trait ManifestParams: Send + Sync {
124    fn skip_manifest(&self) -> bool;
125    fn address(&self) -> Cid;
126    fn set_address(&mut self, addr: Cid);
127    fn get_type(&self) -> &str;
128    fn set_type(&mut self, t: String);
129    fn get_name(&self) -> &str;
130    fn set_name(&mut self, name: String);
131    fn set_access(&mut self, role: String, allowed: Vec<String>);
132    fn get_access(&self, role: &str) -> Option<Vec<String>>;
133    fn get_all_access(&self) -> HashMap<String, Vec<String>>;
134
135    /// Permite downcast seguro para implementações concretas
136    fn as_any(&self) -> &dyn std::any::Any;
137}
138
139impl ManifestParams for CreateAccessControllerOptions {
140    fn skip_manifest(&self) -> bool {
141        self.skip_manifest
142    }
143    fn address(&self) -> Cid {
144        self.address
145    }
146    fn set_address(&mut self, addr: Cid) {
147        self.address = addr;
148    }
149    fn get_type(&self) -> &str {
150        &self.get_type
151    }
152    fn set_type(&mut self, t: String) {
153        self.get_type = t;
154    }
155    fn get_name(&self) -> &str {
156        &self.name
157    }
158    fn set_name(&mut self, name: String) {
159        self.name = name;
160    }
161
162    fn set_access(&mut self, role: String, allowed: Vec<String>) {
163        let mut guard = self.access.lock().expect("Failed to acquire lock");
164        guard.insert(role, allowed);
165    }
166
167    fn get_access(&self, role: &str) -> Option<Vec<String>> {
168        let guard = self.access.lock().expect("Failed to acquire lock");
169        guard.get(role).cloned()
170    }
171
172    fn get_all_access(&self) -> HashMap<String, Vec<String>> {
173        let guard = self.access.lock().expect("Failed to acquire lock");
174        guard.clone()
175    }
176
177    fn as_any(&self) -> &dyn std::any::Any {
178        self
179    }
180}
181
182impl CreateAccessControllerOptions {
183    pub fn new(address: Cid, skip_manifest: bool, manifest_type: String) -> Self {
184        Self {
185            address,
186            skip_manifest,
187            get_type: manifest_type,
188            ..Default::default()
189        }
190    }
191
192    pub fn new_empty() -> Self {
193        Default::default()
194    }
195
196    pub fn new_simple(manifest_type: String, access: HashMap<String, Vec<String>>) -> Self {
197        Self {
198            skip_manifest: true,
199            get_type: manifest_type,
200            access: Arc::new(Mutex::new(access)),
201            ..Default::default()
202        }
203    }
204
205    pub fn from_params(params: &CreateAccessControllerOptions) -> Self {
206        params.clone()
207    }
208}
209
210/// Cria um novo manifesto e retorna seu CID.
211pub async fn create(
212    ipfs: Arc<IpfsClient>,
213    controller_type: String,
214    params: &CreateAccessControllerOptions,
215) -> Result<Cid> {
216    if params.skip_manifest() {
217        return Ok(params.address());
218    }
219
220    // Valida que o controller_type não está vazio
221    if controller_type.is_empty() {
222        return Err(GuardianError::Store(
223            "Controller type cannot be empty".to_string(),
224        ));
225    }
226
227    let manifest = Manifest {
228        get_type: controller_type,
229        params: CreateAccessControllerOptions {
230            skip_manifest: params.skip_manifest(),
231            address: params.address(),
232            get_type: params.get_type().to_string(),
233            name: params.get_name().to_string(),
234            access: params.access.clone(),
235        },
236    };
237
238    // Serializa o manifesto em CBOR
239    let cbor_data = serde_cbor::to_vec(&manifest)
240        .map_err(|e| GuardianError::Store(format!("Failed to serialize manifest: {}", e)))?;
241
242    // Valida que os dados serializados não estão vazios
243    if cbor_data.is_empty() {
244        return Err(GuardianError::Store(
245            "Serialized manifest is empty".to_string(),
246        ));
247    }
248
249    // Armazena no IPFS usando o cliente nativo
250    let response = ipfs
251        .add_bytes(cbor_data)
252        .await
253        .map_err(|e| GuardianError::Store(format!("Failed to store manifest in IPFS: {}", e)))?;
254
255    // Valida que o IPFS retornou um hash válido
256    if response.hash.is_empty() {
257        return Err(GuardianError::Store("IPFS returned empty hash".to_string()));
258    }
259
260    // Converte o hash retornado para CID
261    let cid = Cid::try_from(response.hash.as_str())
262        .map_err(|e| GuardianError::Store(format!("Invalid CID returned from IPFS: {}", e)))?;
263
264    Ok(cid)
265}
266
267/// Recupera um manifesto a partir do seu endereço.
268pub async fn resolve(
269    ipfs: Arc<IpfsClient>,
270    manifest_address: &str,
271    params: &CreateAccessControllerOptions,
272) -> Result<Manifest> {
273    if params.skip_manifest() {
274        if params.get_type().is_empty() {
275            return Err(GuardianError::Store(
276                "Sem manifesto, o tipo do controlador de acesso é obrigatório".to_string(),
277            ));
278        }
279
280        return Ok(Manifest {
281            get_type: params.get_type().to_string(),
282            params: params.clone(),
283        });
284    }
285
286    // Valida que o endereço não está vazio
287    if manifest_address.is_empty() {
288        return Err(GuardianError::Store(
289            "Manifest address cannot be empty".to_string(),
290        ));
291    }
292
293    // Remove o prefixo /ipfs/ se existir
294    let hash = if let Some(stripped) = manifest_address.strip_prefix("/ipfs/") {
295        stripped
296    } else {
297        manifest_address
298    };
299
300    let cid = Cid::try_from(hash)
301        .map_err(|e| GuardianError::Store(format!("Invalid CID format: {}", e)))?;
302
303    // Busca os dados do manifesto no IPFS
304    use tokio::io::AsyncReadExt;
305
306    let mut data_reader = ipfs.cat(&cid.to_string()).await.map_err(|e| {
307        GuardianError::Store(format!("Failed to retrieve manifest from IPFS: {}", e))
308    })?;
309    let mut data_bytes = Vec::new();
310    data_reader
311        .read_to_end(&mut data_bytes)
312        .await
313        .map_err(|e| GuardianError::Store(format!("Failed to read manifest data: {}", e)))?;
314
315    // Valida que os dados não estão vazios
316    if data_bytes.is_empty() {
317        return Err(GuardianError::Store(
318            "Retrieved manifest data is empty".to_string(),
319        ));
320    }
321
322    // Deserializa o manifesto a partir dos dados CBOR
323    let manifest: Manifest = serde_cbor::from_slice(&data_bytes)
324        .map_err(|e| GuardianError::Store(format!("Failed to deserialize manifest: {}", e)))?;
325
326    // Validação adicional do manifesto
327    if manifest.get_type.is_empty() {
328        return Err(GuardianError::Store(
329            "Manifest type cannot be empty".to_string(),
330        ));
331    }
332
333    Ok(manifest)
334}
335
336/// Função utilitária para criar e validar um manifesto
337pub fn create_manifest_with_validation(
338    controller_type: String,
339    params: CreateAccessControllerOptions,
340) -> Result<Manifest> {
341    // Validações básicas
342    if controller_type.is_empty() {
343        return Err(GuardianError::Store(
344            "Controller type cannot be empty".to_string(),
345        ));
346    }
347
348    if controller_type.len() > 255 {
349        return Err(GuardianError::Store(
350            "Controller type too long (max 255 characters)".to_string(),
351        ));
352    }
353
354    // Valida que o tipo é um dos tipos conhecidos
355    let valid_types = ["ipfs", "GuardianDB", "simple"];
356    if !valid_types.contains(&controller_type.as_str()) {
357        return Err(GuardianError::Store(format!(
358            "Unknown controller type: {}",
359            controller_type
360        )));
361    }
362
363    Ok(Manifest {
364        get_type: controller_type,
365        params,
366    })
367}
368
369#[cfg(test)]
370mod tests {
371    use super::*;
372    use std::collections::HashMap;
373
374    #[test]
375    fn test_cid_serialization_deserialization() {
376        // Demonstra que CID serializa/deserializa nativamente sem implementação customizada
377        let mut access = HashMap::new();
378        access.insert("write".to_string(), vec!["test_key".to_string()]);
379
380        let original_cid = Cid::default();
381        let options = CreateAccessControllerOptions {
382            skip_manifest: false,
383            address: original_cid,
384            get_type: "test".to_string(),
385            name: "test_controller".to_string(),
386            access: Arc::new(std::sync::Mutex::new(access)),
387        };
388
389        // Serialização JSON (funciona nativamente)
390        let json =
391            serde_json::to_string(&options).expect("CID serializa sem implementação customizada");
392        let deserialized: CreateAccessControllerOptions =
393            serde_json::from_str(&json).expect("CID deserializa sem implementação customizada");
394
395        assert_eq!(deserialized.address, original_cid);
396        assert_eq!(deserialized.get_type, "test");
397        assert_eq!(deserialized.name, "test_controller");
398
399        // Serialização CBOR (também funciona nativamente)
400        let cbor = serde_cbor::to_vec(&options).expect("CID serializa em CBOR nativamente");
401        let cbor_deserialized: CreateAccessControllerOptions =
402            serde_cbor::from_slice(&cbor).expect("CID deserializa de CBOR nativamente");
403
404        assert_eq!(cbor_deserialized.address, original_cid);
405    }
406}