1use core::fmt;
13use std::collections::HashMap;
14use std::collections::HashSet;
15use std::sync::Arc;
16
17use serde::{Deserialize, Serialize};
18
19use crate::errors::*;
20#[allow(unused_imports)]
21use crate::log::*;
22use crate::store::Store;
23use crate::types::*;
24
25impl RepositoryV0 {
26 pub fn new_with_meta(id: &PubKey, metadata: &Vec<u8>) -> RepositoryV0 {
27 RepositoryV0 {
28 id: id.clone(),
29 metadata: metadata.clone(),
30 verification_program: vec![],
31 fork_of: vec![],
32 creator: None,
33 }
34 }
35}
36
37impl Repository {
38 pub fn new(id: &RepoId) -> Self {
39 Repository::V0(RepositoryV0 {
40 id: id.clone(),
41 verification_program: vec![],
42 creator: None,
43 fork_of: vec![],
44 metadata: vec![],
45 })
46 }
47 pub fn new_with_meta(id: &PubKey, metadata: &Vec<u8>) -> Repository {
48 Repository::V0(RepositoryV0::new_with_meta(id, metadata))
49 }
50 pub fn id(&self) -> &PubKey {
51 match self {
52 Self::V0(v0) => &v0.id,
53 }
54 }
55}
56
57#[derive(Debug)]
58pub struct UserInfo {
59 pub permissions: HashMap<PermissionV0, Vec<u8>>,
61 pub id: UserId,
62}
63
64impl UserInfo {
65 pub fn has_any_perm(&self, perms: &HashSet<PermissionV0>) -> Result<(), NgError> {
66 if self.has_perm(&PermissionV0::Owner).is_ok() {
68 return Ok(());
69 }
70 let is_admin = self.has_perm(&PermissionV0::Admin).is_ok();
71 let has_perms: HashSet<&PermissionV0> = self.permissions.keys().collect();
74 for perm in perms {
76 if is_admin && perm.is_delegated_by_admin() || has_perms.contains(perm) {
77 return Ok(());
78 }
79 }
80 Err(NgError::PermissionDenied)
84 }
85 pub fn has_perm(&self, perm: &PermissionV0) -> Result<&Vec<u8>, NgError> {
86 self.permissions.get(perm).ok_or(NgError::PermissionDenied)
87 }
88}
89
90#[derive(Debug, Clone)]
91pub struct BranchInfo {
92 pub id: BranchId,
93
94 pub branch_type: BranchType,
95
96 pub crdt: BranchCrdt,
97
98 pub topic: Option<TopicId>,
99
100 pub topic_priv_key: Option<BranchWriteCapSecret>,
101
102 pub read_cap: Option<ReadCap>,
103
104 pub fork_of: Option<BranchId>,
105
106 pub merged_in: Option<BranchId>,
107
108 pub current_heads: Vec<ObjectRef>,
109
110 pub commits_nbr: u64,
111}
112
113#[derive(Debug)]
115pub struct Repo {
116 pub id: RepoId,
117 pub repo_def: Repository,
119
120 pub read_cap: Option<ReadCap>,
121
122 pub write_cap: Option<RepoWriteCapSecret>,
123
124 pub signer: Option<SignerCap>,
125
126 pub certificate_ref: Option<ObjectRef>,
127
128 pub members: HashMap<Digest, UserInfo>,
129
130 pub branches: HashMap<BranchId, BranchInfo>,
131
132 pub opened_branches: HashMap<BranchId, bool>,
136
137 pub store: Arc<Store>,
148}
149
150impl fmt::Display for Repo {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 writeln!(f, "====== Repo ====== {}", self.id)?;
153
154 write!(f, "== repo_def: {}", self.repo_def)?;
155
156 if self.signer.is_some() {
157 writeln!(f, "== signer: {:?}", self.signer)?;
158 }
159
160 writeln!(f, "== members: {:?}", self.members)?;
161
162 Ok(())
163 }
164}
165
166#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
167pub struct CommitInfo {
168 pub past: Vec<ObjectId>,
169 pub key: ObjectKey,
170 pub signature: Option<ObjectRef>,
171 pub author: String,
172 pub timestamp: Timestamp,
173 pub final_consistency: bool,
174 pub commit_type: CommitType,
175 pub branch: Option<ObjectId>,
176 pub x: u32,
177 pub y: u32,
178}
179
180impl Repo {
181 #[cfg(any(test, feature = "testing"))]
182 #[allow(deprecated)]
183 pub fn new_with_perms(perms: &[PermissionV0], store: Arc<Store>) -> Self {
184 let pub_key = PubKey::nil();
185 Self::new_with_member(&pub_key, &pub_key, perms, store)
186 }
187
188 pub(crate) fn get_user_string(&self, user_hash: &Digest) -> String {
189 self.members
190 .get(user_hash)
191 .map_or_else(|| format!("t:{user_hash}"), |info| format!("i:{}", info.id))
192 }
193
194 fn load_causal_past(
195 &self,
196 recursor: &mut Vec<(BlockRef, Option<ObjectId>)>,
197 visited: &mut HashMap<ObjectId, (HashSet<ObjectId>, CommitInfo)>,
198 signatures: &mut HashMap<ObjectId, ObjectRef>,
199 ) -> Result<Option<ObjectId>, VerifierError> {
200 let mut root = None;
201 while let Some((next_ref, future)) = recursor.pop() {
202 if let Ok(cobj) = Commit::load(next_ref, &self.store, true) {
203 let id = cobj.id().unwrap();
204 if let Some((future_set, info)) = visited.get_mut(&id) {
205 if let Some(f) = future {
207 future_set.insert(f);
208 }
209 if let Some(sign) = signatures.remove(&id) {
210 info.signature = Some(sign);
211 }
212 } else {
213 let commit_type = cobj.get_type().unwrap();
214 let acks = cobj.acks();
215 let (past, real_acks, next_future) = match commit_type {
219 CommitType::SyncSignature => {
220 assert_eq!(acks.len(), 1);
221 let dep = cobj.deps();
222 assert_eq!(dep.len(), 1);
223 let mut current_commit = dep[0].clone();
224 let sign_ref = cobj.get_signature_reference().unwrap();
225 let real_acks;
226 let mut future = id;
227 loop {
228 let o = Commit::load(current_commit.clone(), &self.store, true)?;
229 let deps = o.deps();
230 let commit_info = CommitInfo {
231 past: deps.iter().map(|r| r.id.clone()).collect(),
232 key: o.key().unwrap(),
233 signature: Some(sign_ref.clone()),
234 author: self.get_user_string(o.author()),
235 timestamp: o.timestamp(),
236 final_consistency: o.final_consistency(),
237 commit_type: o.get_type().unwrap(),
238 branch: None,
239 x: 0,
240 y: 0,
241 };
242 let id = o.id().unwrap();
243
244 visited.insert(id, ([future].into(), commit_info));
245 future = id;
246 if id == acks[0].id {
247 real_acks = o.acks();
248 break;
249 }
250 assert_eq!(deps.len(), 1);
251 current_commit = deps[0].clone();
252 }
253 (vec![dep[0].id], real_acks, future)
254 }
255 CommitType::AsyncSignature => {
256 let past: Vec<ObjectId> = acks.iter().map(|r| r.id.clone()).collect();
257 let sign = cobj.get_signature_reference().unwrap();
258 for p in cobj.deps().iter() {
259 signatures.insert(p.id, sign.clone());
260 }
262 (past, acks, id)
263 }
264 _ => (acks.iter().map(|r| r.id.clone()).collect(), acks, id),
265 };
266
267 let commit_info = CommitInfo {
268 past,
269 key: cobj.key().unwrap(),
270 signature: signatures.remove(&id),
271 author: self.get_user_string(cobj.author()),
272 timestamp: cobj.timestamp(),
273 final_consistency: cobj.final_consistency(),
274 commit_type,
275 branch: None,
276 x: 0,
277 y: 0,
278 };
279 visited.insert(id, (future.map_or([].into(), |f| [f].into()), commit_info));
280 if real_acks.is_empty() && root.is_none() {
281 root = Some(next_future);
282 }
283 recursor.extend(real_acks.into_iter().map(|br| (br, Some(next_future))));
284 }
291 }
292 }
293 Ok(root)
294 }
295
296 fn past_is_all_in(
297 past: &Vec<ObjectId>,
298 already_in: &HashMap<ObjectId, ObjectId>,
299 coming_from: &ObjectId,
300 ) -> bool {
301 for p in past {
302 if !already_in.contains_key(p) && p != coming_from {
303 return false;
304 }
305 }
306 true
307 }
308
309 fn collapse(
310 id: &ObjectId,
311 dag: &mut HashMap<ObjectId, (HashSet<ObjectId>, CommitInfo)>,
312 already_in: &mut HashMap<ObjectId, ObjectId>,
313 branches_order: &mut Vec<Option<ObjectId>>,
314 branches: &mut HashMap<ObjectId, usize>,
315 ) -> Vec<(ObjectId, CommitInfo)> {
317 let (_, c) = dag.get(id).unwrap();
318 if c.past.len() > 1 && !Self::past_is_all_in(&c.past, already_in, id) {
320 vec![]
323 } else {
324 let (future, mut info) = dag.remove(id).unwrap();
325 let mut branch = match info.past.len() {
326 0 => *id,
327 _ => info.branch.unwrap(),
328 };
345 info.branch = Some(branch.clone());
346 let mut res = vec![(*id, info)];
352 let mut first_child_branch = branch.clone();
353 already_in.insert(*id, branch);
354 let mut future = Vec::from_iter(future);
355 future.sort();
356 let mut iterator = future.iter().peekable();
358 while let Some(child) = iterator.next() {
359 {
361 let (_, info) = dag.get_mut(child).unwrap();
363 if let Some(b) = info.branch.to_owned() {
364 let previous_ordinal = branches.get(&b).unwrap();
365 let new_ordinal = branches.get(&branch).unwrap();
366 let close = if previous_ordinal > new_ordinal {
367 let _ = info.branch.insert(branch);
368 &b
377 } else {
378 if first_child_branch == branch {
380 first_child_branch = b;
381 }
382 &branch
390 };
391 let i = branches.get(close).unwrap();
392 branches_order.get_mut(*i).unwrap().take();
393 } else {
394 let _ = info.branch.insert(branch);
395 }
396 }
397 res.append(&mut Self::collapse(
407 child,
408 dag,
409 already_in,
410 branches_order,
411 branches,
412 ));
414 if let Some(next) = iterator.peek() {
425 branch = **next;
426 if branches.contains_key(*next) {
427 continue;
428 }
429 let mut branch_inserted = false;
430 let mut first_child_branch_passed = false;
431 for (i, next_branch) in branches_order.iter_mut().enumerate() {
432 if let Some(b) = next_branch {
433 if b == &first_child_branch {
434 first_child_branch_passed = true;
435 }
437 }
438 if next_branch.is_none() && first_child_branch_passed {
439 let _ = next_branch.insert(branch.clone());
441 branches.insert(branch, i);
442 branch_inserted = true;
443 break;
444 }
445 }
446 if !branch_inserted {
447 branches_order.push(Some(branch.clone()));
454 branches.insert(branch, branches_order.len() - 1);
455 }
456 }
457 }
458 res
459 }
460 }
461
462 pub fn history_at_heads(
463 &self,
464 heads: &[ObjectRef],
465 ) -> Result<(Vec<(ObjectId, CommitInfo)>, Vec<Option<ObjectId>>), VerifierError> {
466 assert!(!heads.is_empty());
467 let mut visited = HashMap::new();
471 let mut root = None;
472 let mut recursor: Vec<(BlockRef, Option<ObjectId>)> =
473 heads.iter().map(|h| (h.clone(), None)).collect();
474 let mut signatures: HashMap<ObjectId, ObjectRef> = HashMap::new();
475 let r = self.load_causal_past(&mut recursor, &mut visited, &mut signatures)?;
476 if r.is_some() {
477 root = r;
478 }
479 if root.is_none() {
493 return Err(VerifierError::MalformedDag);
494 }
495 let root = root.unwrap();
496
497 let mut already_in: HashMap<ObjectId, ObjectId> = HashMap::new();
498 let mut branches_order: Vec<Option<ObjectId>> = vec![Some(root.clone())];
499 let mut branches: HashMap<ObjectId, usize> = HashMap::from([(root.clone(), 0)]);
500 let mut commits = Self::collapse(
502 &root,
503 &mut visited,
504 &mut already_in,
505 &mut branches_order,
506 &mut branches,
507 );
509 for (i, (_, commit)) in commits.iter_mut().enumerate() {
510 commit.y = i as u32;
511 commit.x = *branches.get(commit.branch.as_ref().unwrap()).unwrap() as u32;
512 }
513 Ok((commits, branches_order))
514 }
515
516 pub fn update_branch_current_heads(
517 &mut self,
518 branch: &BranchId,
519 commit_ref: ObjectRef,
520 past: Vec<ObjectRef>,
521 ) -> Result<Vec<ObjectRef>, VerifierError> {
522 if let Some(branch) = self.branches.get_mut(branch) {
524 let mut set: HashSet<&ObjectRef> = HashSet::from_iter(branch.current_heads.iter());
525 for p in past {
526 set.remove(&p);
527 }
528 let already_in_heads = set.contains(&commit_ref);
529 branch.current_heads = set.into_iter().cloned().collect();
530 if !already_in_heads {
531 branch.current_heads.push(commit_ref);
532 branch.commits_nbr += 1;
533 }
534 Ok(branch.current_heads.to_vec())
536 } else {
537 Err(VerifierError::BranchNotFound)
538 }
539 }
540
541 pub fn new_with_member(
542 repo_id: &PubKey,
543 member: &UserId,
544 perms: &[PermissionV0],
545 store: Arc<Store>,
546 ) -> Self {
547 let mut members = HashMap::new();
548 let permissions = HashMap::from_iter(
549 perms
550 .iter()
551 .map(|p| (*p, vec![]))
552 .collect::<Vec<(PermissionV0, Vec<u8>)>>()
553 .iter()
554 .cloned(),
555 );
556 let overlay = store.get_store_repo().overlay_id_for_read_purpose();
557 let member_hash = CommitContent::author_digest(member, overlay);
558 members.insert(
560 member_hash,
561 UserInfo {
562 id: *member,
563 permissions,
564 },
565 );
566 Self {
567 id: repo_id.clone(),
568 repo_def: Repository::new(&repo_id),
569 members,
570 store,
571 signer: None,
572 certificate_ref: None,
573 read_cap: None,
574 write_cap: None,
575 branches: HashMap::new(),
576 opened_branches: HashMap::new(),
577 }
579 }
580
581 pub fn verify_permission(&self, commit: &Commit) -> Result<(), NgError> {
582 let content_author = commit.content_v0().author;
583 let body = commit.load_body(&self.store)?;
584 match self.members.get(&content_author) {
585 Some(info) => return info.has_any_perm(&body.required_permission()),
586 None => {}
587 }
588 Err(NgError::PermissionDenied)
589 }
590
591 pub fn member_pubkey(&self, hash: &Digest) -> Result<UserId, NgError> {
592 match self.members.get(hash) {
593 Some(user_info) => Ok(user_info.id),
594 None => Err(NgError::NotFound),
595 }
596 }
597
598 pub fn branch(&self, id: &BranchId) -> Result<&BranchInfo, NgError> {
599 self.branches.get(id).ok_or(NgError::BranchNotFound)
601 }
602
603 pub fn branch_mut(&mut self, id: &BranchId) -> Result<&mut BranchInfo, NgError> {
604 self.branches.get_mut(id).ok_or(NgError::BranchNotFound)
606 }
607
608 pub fn overlay_branch(&self) -> Option<&BranchInfo> {
609 for (_, branch) in self.branches.iter() {
610 if branch.branch_type == BranchType::Overlay {
611 return Some(branch);
612 }
613 }
614 None
615 }
616
617 pub fn user_branch(&self) -> Option<&BranchInfo> {
618 for (_, branch) in self.branches.iter() {
619 if branch.branch_type == BranchType::User {
620 return Some(branch);
621 }
622 }
623 None
624 }
625
626 pub fn main_branch(&self) -> Option<&BranchInfo> {
627 for (_, branch) in self.branches.iter() {
628 if branch.branch_type == BranchType::Main {
629 return Some(branch);
630 }
631 }
632 None
633 }
634
635 pub fn store_branch(&self) -> Option<&BranchInfo> {
636 for (_, branch) in self.branches.iter() {
637 if branch.branch_type == BranchType::Store {
638 return Some(branch);
639 }
640 }
641 None
642 }
643
644 pub fn header_branch(&self) -> Option<&BranchInfo> {
645 for (_, branch) in self.branches.iter() {
646 if branch.branch_type == BranchType::Header {
647 return Some(branch);
648 }
649 }
650 None
651 }
652
653 pub fn root_branch(&self) -> Option<&BranchInfo> {
654 for (_, branch) in self.branches.iter() {
655 if branch.branch_type == BranchType::Root {
656 return Some(branch);
657 }
658 }
659 None
660 }
661
662 pub fn overlay_branch_read_cap(&self) -> Option<&ReadCap> {
663 match self.overlay_branch() {
664 Some(bi) => Some(bi.read_cap.as_ref().unwrap()),
665 None => self.read_cap.as_ref(), }
667 }
668
669 pub fn branch_is_opened(&self, branch: &BranchId) -> bool {
670 self.opened_branches.contains_key(branch)
671 }
672
673 pub fn branch_is_opened_as_publisher(&self, branch: &BranchId) -> bool {
674 match self.opened_branches.get(branch) {
675 Some(val) => *val,
676 None => false,
677 }
678 }
679
680 }