Skip to main content

deaddrop_core/
space.rs

1//! Signed Space membership records. Payload-agnostic shared namespaces.
2
3use crate::crypto::{CryptoProvider, DefaultProvider, PrivateIdentity};
4use crate::{PeerId, Result};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum SpaceKind {
10    Private,
11    InviteOnly,
12    Public,
13    Ephemeral,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct SpaceRecord {
18    pub name: String,
19    pub kind: SpaceKind,
20    pub members: Vec<PeerId>,
21    pub retention: String,
22    pub created_at: u64,
23    pub founder: PeerId,
24    #[serde(with = "serde_bytes")]
25    pub signature: [u8; 64],
26}
27
28impl SpaceRecord {
29    pub fn issue(
30        author: &PrivateIdentity,
31        name: String,
32        kind: SpaceKind,
33        members: Vec<PeerId>,
34        retention: String,
35        now: u64,
36    ) -> Self {
37        let mut rec = Self {
38            name,
39            kind,
40            members,
41            retention,
42            created_at: now,
43            founder: author.peer_id,
44            signature: [0; 64],
45        };
46        rec.signature = DefaultProvider.sign(&author.signing_key(), &rec.preimage());
47        rec
48    }
49
50    pub fn preimage(&self) -> Vec<u8> {
51        let mut b = Vec::from(&b"ddp-space-v2"[..]);
52        b.extend_from_slice(self.name.as_bytes());
53        b.extend_from_slice(self.founder.as_bytes());
54        b.extend_from_slice(&self.created_at.to_be_bytes());
55        b
56    }
57
58    pub fn verify(&self, founder_pk: &[u8; 32]) -> Result<()> {
59        DefaultProvider.verify(founder_pk, &self.preimage(), &self.signature)
60    }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct SpaceInvite {
65    pub space: String,
66    pub invitee: Option<PeerId>,
67    pub issued_by: PeerId,
68    pub created_at: u64,
69    #[serde(with = "serde_bytes")]
70    pub signature: [u8; 64],
71}
72
73impl SpaceInvite {
74    pub fn issue(
75        author: &PrivateIdentity,
76        space: String,
77        invitee: Option<PeerId>,
78        now: u64,
79    ) -> Self {
80        let mut inv = Self {
81            space,
82            invitee,
83            issued_by: author.peer_id,
84            created_at: now,
85            signature: [0; 64],
86        };
87        let mut msg = Vec::from(&b"ddp-space-invite-v2"[..]);
88        msg.extend_from_slice(inv.space.as_bytes());
89        msg.extend_from_slice(author.peer_id.as_bytes());
90        inv.signature = DefaultProvider.sign(&author.signing_key(), &msg);
91        inv
92    }
93}