libsignal_service/groups_v2/
model.rs1use std::{convert::TryFrom, convert::TryInto};
2
3use libsignal_protocol::{Aci, Pni, ServiceId};
4use serde::{Deserialize, Serialize};
5use zkgroup::profiles::ProfileKey;
6
7use crate::sender::GroupV2Id;
8
9use super::GroupDecodingError;
10
11#[derive(Copy, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
12pub enum Role {
13 Unknown,
14 Default,
15 Administrator,
16}
17
18#[derive(derive_more::Debug, Clone, Deserialize, Serialize)]
19pub struct Member {
20 #[serde(with = "aci_serde")]
21 pub aci: Aci,
22 pub role: Role,
23 #[debug(ignore)]
24 pub profile_key: ProfileKey,
25 pub joined_at_revision: u32,
26}
27
28impl PartialEq for Member {
29 fn eq(&self, other: &Self) -> bool {
30 self.aci == other.aci
31 }
32}
33
34mod aci_serde {
35 use super::*;
36 use serde::{Deserializer, Serializer};
37
38 pub fn serialize<S>(p: &Aci, s: S) -> Result<S::Ok, S::Error>
39 where
40 S: Serializer,
41 {
42 s.serialize_str(&p.service_id_string())
43 }
44
45 pub fn deserialize<'de, D>(d: D) -> Result<Aci, D::Error>
46 where
47 D: Deserializer<'de>,
48 {
49 let s = std::borrow::Cow::<str>::deserialize(d)?;
52 match Aci::parse_from_service_id_string(&s) {
53 Some(aci) => Ok(aci),
54 None => Err(serde::de::Error::custom("Invalid ACI string")),
55 }
56 }
57}
58
59#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct PendingMember {
61 pub address: ServiceId,
62 pub role: Role,
63 pub added_by_aci: Aci,
64 pub timestamp: u64,
65}
66
67#[derive(derive_more::Debug, Clone)]
68pub struct RequestingMember {
69 pub aci: Aci,
70 #[debug(ignore)]
71 pub profile_key: ProfileKey,
72 pub timestamp: u64,
73}
74
75impl PartialEq for RequestingMember {
76 fn eq(&self, other: &Self) -> bool {
77 self.aci == other.aci
78 }
79}
80
81#[derive(Debug, Clone)]
82pub struct BannedMember {
83 pub service_id: ServiceId,
84 pub timestamp: u64,
85}
86
87impl PartialEq for BannedMember {
88 fn eq(&self, other: &Self) -> bool {
89 self.service_id == other.service_id
90 }
91}
92
93#[derive(derive_more::Debug, Clone)]
94pub struct PromotedMember {
95 pub aci: Aci,
96 pub pni: Pni,
97 #[debug(ignore)]
98 pub profile_key: ProfileKey,
99}
100
101impl PartialEq for PromotedMember {
102 fn eq(&self, other: &Self) -> bool {
103 self.aci == other.aci && self.pni == other.pni
104 }
105}
106
107#[derive(Copy, Debug, Clone, PartialEq, Serialize, Deserialize)]
108pub enum AccessRequired {
109 Unknown,
110 Any,
111 Member,
112 Administrator,
113 Unsatisfiable,
114}
115
116#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
117pub struct AccessControl {
118 pub attributes: AccessRequired,
119 pub members: AccessRequired,
120 pub add_from_invite_link: AccessRequired,
121}
122
123#[derive(Debug, Clone, PartialEq)]
124pub struct Group {
125 pub title: String,
126 pub avatar: String,
127 pub disappearing_messages_timer: Option<Timer>,
128 pub access_control: Option<AccessControl>,
129 pub revision: u32,
130 pub members: Vec<Member>,
131 pub pending_members: Vec<PendingMember>,
132 pub requesting_members: Vec<RequestingMember>,
133 pub invite_link_password: Vec<u8>,
134 pub description: Option<String>,
135 pub announcements_only: bool,
136 pub banned_members: Vec<BannedMember>,
137}
138
139#[derive(Debug, Clone)]
140pub struct GroupChanges {
141 pub group_id: GroupV2Id,
142 pub editor: Aci,
143 pub revision: u32,
144 pub changes: Vec<GroupChange>,
145 pub change_epoch: u32,
146}
147
148#[derive(derive_more::Debug, Clone)]
149pub enum GroupChange {
150 NewMember(Member),
151 DeleteMember(Aci),
152 ModifyMemberRole {
153 aci: Aci,
154 role: Role,
155 },
156 ModifyMemberProfileKey {
157 aci: Aci,
158 #[debug(ignore)]
159 profile_key: ProfileKey,
160 },
161 NewPendingMember(PendingMember),
162 DeletePendingMember(ServiceId),
163 PromotePendingMember {
164 address: ServiceId,
165 #[debug(ignore)]
166 profile_key: ProfileKey,
167 },
168 Title(String),
169 Avatar(String),
170 Timer(Option<Timer>),
171 AttributeAccess(AccessRequired),
172 MemberAccess(AccessRequired),
173 InviteLinkAccess(AccessRequired),
174 NewRequestingMember(RequestingMember),
175 DeleteRequestingMember(Aci),
176 PromoteRequestingMember {
177 aci: Aci,
178 role: Role,
179 },
180 InviteLinkPassword(String),
181 Description(Option<String>),
182 AnnouncementOnly(bool),
183 AddBannedMember(BannedMember),
184 DeleteBannedMember(ServiceId),
185 PromotePendingPniAciMemberProfileKey(PromotedMember),
186}
187
188#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
189pub struct Timer {
190 pub duration: u32,
191}
192
193impl TryFrom<i32> for Role {
196 type Error = GroupDecodingError;
197
198 fn try_from(value: i32) -> Result<Self, Self::Error> {
199 use crate::proto::member::Role::*;
200 match crate::proto::member::Role::try_from(value) {
201 Ok(Unknown) => Ok(Role::Unknown),
202 Ok(Default) => Ok(Role::Default),
203 Ok(Administrator) => Ok(Role::Administrator),
204 Err(_e) => Err(GroupDecodingError::WrongEnumValue),
205 }
206 }
207}
208
209impl From<Role> for i32 {
210 fn from(val: Role) -> Self {
211 use crate::proto::member::Role::*;
212 match val {
213 Role::Unknown => Unknown,
214 Role::Default => Default,
215 Role::Administrator => Administrator,
216 }
217 .into()
218 }
219}
220
221impl TryFrom<i32> for AccessRequired {
222 type Error = GroupDecodingError;
223
224 fn try_from(value: i32) -> Result<Self, Self::Error> {
225 use crate::proto::access_control::AccessRequired::*;
226 match crate::proto::access_control::AccessRequired::try_from(value) {
227 Ok(Unknown) => Ok(AccessRequired::Unknown),
228 Ok(Any) => Ok(AccessRequired::Any),
229 Ok(Member) => Ok(AccessRequired::Member),
230 Ok(Administrator) => Ok(AccessRequired::Administrator),
231 Ok(Unsatisfiable) => Ok(AccessRequired::Unsatisfiable),
232 Err(_e) => Err(GroupDecodingError::WrongEnumValue),
233 }
234 }
235}
236
237impl From<AccessRequired> for i32 {
238 fn from(val: AccessRequired) -> Self {
239 use crate::proto::access_control::AccessRequired::*;
240 match val {
241 AccessRequired::Unknown => Unknown,
242 AccessRequired::Any => Any,
243 AccessRequired::Member => Member,
244 AccessRequired::Administrator => Administrator,
245 AccessRequired::Unsatisfiable => Unsatisfiable,
246 }
247 .into()
248 }
249}
250
251impl TryFrom<crate::proto::AccessControl> for AccessControl {
252 type Error = GroupDecodingError;
253
254 fn try_from(
255 value: crate::proto::AccessControl,
256 ) -> Result<Self, Self::Error> {
257 Ok(Self {
258 attributes: value.attributes.try_into()?,
259 members: value.members.try_into()?,
260 add_from_invite_link: value.add_from_invite_link.try_into()?,
261 })
262 }
263}