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