Skip to main content

coven_format/
objects.rs

1//! Signed join request frames (D8).
2
3use crate::admin::MemberPublicKeys;
4use crate::codes::InviteKind;
5use crate::error::Error;
6use crate::value::name;
7use crate::wire::{wire_struct, Decoder, Encoder, Wire};
8use coven_foundation::id_source::{DeviceId, InviteId, MemberId};
9
10/// A new person's request, encrypted with the invite-derived key and signed (§13.2).
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct JoinRequest {
13    /// The invite this request answers.
14    pub invite: InviteId,
15    /// The member id fixed by the invite: fresh for an addition, or the
16    /// existing member's for a re-binding (D8, D13).
17    pub member: MemberId,
18    /// The requested public pair; it verifies this request's signature.
19    pub keys: MemberPublicKeys,
20    /// The joining installation's own id, fixed when the join begins: the
21    /// approval registers it (D6).
22    pub device: DeviceId,
23    /// The new device's name shown to the approving admin.
24    pub device_name: String,
25    /// Who asks: a new person with the name they typed, or a member
26    /// recovering.
27    pub joiner: Joiner,
28}
29wire_struct!(JoinRequest, invite, member, keys, device, device_name => crate::wire::get_name, joiner);
30impl JoinRequest {
31    pub(crate) fn validate(&self) -> Result<(), Error> {
32        name(&self.device_name)?;
33        self.joiner.validate()
34    }
35}
36
37/// Who a join request is for (§13.2). The invite's kind fixes which a request
38/// may carry.
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub enum Joiner {
41    /// A new person, with the name they typed: the admin sees it with the
42    /// request, and the app makes their profile with it.
43    NewPerson {
44        /// The name, which follows the `name` rule (D2).
45        name: String,
46    },
47    /// An existing member, whose profile already has a name: the request
48    /// carries none.
49    Recovery,
50}
51impl Joiner {
52    /// The kind of invite this request answers.
53    pub fn kind(&self) -> InviteKind {
54        match self {
55            Self::NewPerson { .. } => InviteKind::NewPerson,
56            Self::Recovery => InviteKind::Recovery,
57        }
58    }
59    fn validate(&self) -> Result<(), Error> {
60        match self {
61            Self::NewPerson { name: person } => name(person),
62            Self::Recovery => Ok(()),
63        }
64    }
65}
66impl Wire for Joiner {
67    fn put(&self, out: &mut Encoder) -> Result<(), Error> {
68        match self {
69            Self::Recovery => 0u8.put(out),
70            Self::NewPerson { name: person } => {
71                1u8.put(out)?;
72                person.put(out)
73            }
74        }
75    }
76    fn get(input: &mut Decoder<'_>) -> Result<Self, Error> {
77        match u8::get(input)? {
78            0 => Ok(Self::Recovery),
79            1 => Ok(Self::NewPerson { name: crate::wire::get_name(input)? }),
80            tag => Err(Error::UnknownTag { field: "joiner", tag }),
81        }
82    }
83}
84
85#[cfg(test)]
86#[path = "objects_tests.rs"]
87mod tests;