diff --git a/keyhive_core/src/keyhive.rs b/keyhive_core/src/keyhive.rs index 82437cfa..ea499e0f 100644 --- a/keyhive_core/src/keyhive.rs +++ b/keyhive_core/src/keyhive.rs @@ -424,74 +424,10 @@ impl< agent: &Agent, ) -> BTreeMap> { let mut caps: BTreeMap> = BTreeMap::new(); - let mut seen: HashSet = HashSet::new(); - - #[allow(clippy::type_complexity)] - let mut explore: Vec<(Rc>>, Access)> = vec![]; for doc in self.docs.values() { - seen.insert(doc.clone().borrow().agent_id()); - - let doc_id = doc.borrow().doc_id(); - - if let Some(proofs) = doc.borrow().members().get(&agent.id()) { - for proof in proofs { - caps.insert( - doc_id, - Ability { - doc, - can: proof.payload().can, - }, - ); - } - } - } - - for group in self.groups.values() { - seen.insert(group.borrow().agent_id()); - - if let Some(proofs) = group.borrow().members().get(&agent.id()) { - for proof in proofs { - explore.push((group.dupe(), proof.payload().can)); - } - } - } - - while let Some((group, _access)) = explore.pop() { - for doc in self.docs.values() { - if seen.contains(&doc.borrow().agent_id()) { - continue; - } - - let doc_id = doc.borrow().doc_id(); - - if let Some(proofs) = doc.borrow().members().get(&agent.id()) { - for proof in proofs { - caps.insert( - doc_id, - Ability { - doc, - can: proof.payload.can, - }, - ); - } - } - } - - for (group_id, focus_group) in self.groups.iter() { - if seen.contains(&focus_group.borrow().agent_id()) { - continue; - } - - if group.borrow().id() == (*group_id).into() { - continue; - } - - if let Some(proofs) = focus_group.borrow().members().get(&agent.id()) { - for proof in proofs { - explore.push((focus_group.dupe(), proof.payload.can)); - } - } + if let Some((_, cap)) = doc.borrow().transitive_members().get(&agent.id()) { + caps.insert(doc.borrow().doc_id(), Ability { doc, can: *cap }); } } diff --git a/keyhive_core/tests/transitive_access.rs b/keyhive_core/tests/transitive_access.rs new file mode 100644 index 00000000..f346f95f --- /dev/null +++ b/keyhive_core/tests/transitive_access.rs @@ -0,0 +1,49 @@ +use std::{cell::RefCell, rc::Rc}; + +use keyhive_core::{ + access::Access, crypto::signer::memory::MemorySigner, keyhive::Keyhive, + listener::no_listener::NoListener, principal::individual::Individual, +}; +use nonempty::nonempty; + +async fn make_keyhive() -> Keyhive { + let sk = MemorySigner::generate(&mut rand::thread_rng()); + Keyhive::generate(sk, NoListener, rand::thread_rng()) + .await + .unwrap() +} + +#[tokio::test] +async fn test_group_members_have_access_to_group_docs() { + let mut alice = make_keyhive().await; + let mut bob = make_keyhive().await; + let bob_contact = bob.contact_card().await.unwrap(); + + let bob_on_alice = Rc::new(RefCell::new(Individual::from(bob_contact))); + assert!(alice.register_individual(bob_on_alice.clone())); + + let group = alice.generate_group(vec![]).await.unwrap(); + alice + .add_member( + bob_on_alice.clone().into(), + &mut group.clone().into(), + Access::Read, + &vec![], + ) + .await + .unwrap(); + let init_content = "hello".as_bytes(); + let init_hash = blake3::hash(init_content); + + let doc = alice + .generate_doc(vec![group.clone().into()], nonempty![*init_hash.as_bytes()]) + .await + .unwrap(); + + let reachable = alice.docs_reachable_by_agent(&bob_on_alice.clone().into()); + assert_eq!(reachable.len(), 1); + assert_eq!( + reachable.get(&doc.borrow().doc_id()).unwrap().can(), + Access::Read + ); +}