libsignal_service/websocket/
account.rs1use chrono::{DateTime, Utc};
2use reqwest::Method;
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6use crate::{
7 content::ServiceError,
8 proto::DeviceName,
9 utils::{
10 serde_device_id, serde_e164, serde_optional_base64,
11 serde_optional_base64_url_safe_no_pad, serde_optional_prost_base64,
12 },
13 websocket,
14};
15
16use super::SignalWebSocket;
17
18#[derive(Debug, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct DeviceId {
21 #[serde(with = "serde_device_id")]
22 pub device_id: libsignal_core::DeviceId,
23}
24
25#[derive(Debug, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct DeviceInfo {
28 #[serde(with = "serde_device_id")]
29 pub id: libsignal_core::DeviceId,
30 pub registration_id: i32,
31 pub name: Option<String>,
32 #[serde(with = "chrono::serde::ts_milliseconds")]
33 pub created_at: DateTime<Utc>,
34 #[serde(with = "chrono::serde::ts_milliseconds")]
35 pub last_seen: DateTime<Utc>,
36}
37
38#[derive(Debug, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub(crate) struct DeviceInfoEncrypted {
41 #[serde(with = "serde_device_id")]
42 pub id: libsignal_core::DeviceId,
43 pub name: Option<String>,
44 pub registration_id: i32,
45 pub created_at_ciphertext: String,
46 #[serde(with = "chrono::serde::ts_milliseconds")]
47 pub last_seen: DateTime<Utc>,
48}
49
50#[derive(Debug, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct AccountAttributes {
54 pub registration_id: u32,
55 pub voice: bool,
56 pub video: bool,
57 pub fetches_messages: bool,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub registration_lock: Option<String>,
60 #[serde(default, with = "serde_optional_base64")]
61 pub unidentified_access_key: Option<Vec<u8>>,
62 pub unrestricted_unidentified_access: bool,
63 pub discoverable_by_phone_number: bool,
64 #[serde(default, skip_serializing_if = "Option::is_none")]
65 pub capabilities: Option<DeviceCapabilities>,
66 #[serde(default, with = "serde_optional_prost_base64")]
67 pub name: Option<DeviceName>,
68 pub pni_registration_id: u32,
69 #[serde(
70 default,
71 with = "serde_optional_base64",
72 skip_serializing_if = "Option::is_none"
73 )]
74 pub recovery_password: Option<Vec<u8>>,
75}
76
77#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
80#[serde(rename_all = "camelCase")]
81pub struct DeviceCapabilities {
82 #[serde(default)]
83 pub storage: bool,
84 #[serde(default)]
85 pub transfer: bool,
86 #[serde(default)]
87 pub attachment_backfill: bool,
88 #[serde(default)]
89 pub spqr: bool,
90 #[serde(default, rename = "profiles_v2")]
92 pub profiles_v2: bool,
93 #[serde(default)]
94 pub username_change_sync_message: bool,
95}
96
97impl Default for DeviceCapabilities {
98 fn default() -> Self {
99 DeviceCapabilities {
100 storage: false,
101 transfer: false,
102 attachment_backfill: false,
103 spqr: true,
104 profiles_v2: false,
105 username_change_sync_message: false,
106 }
107 }
108}
109
110#[cfg(test)]
111mod test {
112 #[test]
113 fn device_capabilities_serialization_weird_casing() {
114 let capabilities = super::DeviceCapabilities::default();
115 let json = serde_json::to_string(&capabilities)
116 .expect("Serialize capabilities");
117 assert!(json.contains("usernameChangeSyncMessage"));
118 assert!(json.contains("profiles_v2"));
119 }
120}
121
122#[derive(Debug, Deserialize)]
123#[serde(rename_all = "camelCase")]
124pub struct WhoAmIResponse {
125 #[serde(rename = "uuid")]
126 pub aci: Uuid,
127 #[serde(default)] pub pni: Uuid,
129 #[serde(with = "serde_e164")]
130 pub number: libsignal_core::E164,
131 #[serde(default, with = "serde_optional_base64_url_safe_no_pad")]
133 pub username_hash: Option<Vec<u8>>,
134 #[serde(default)]
139 pub username_link_handle: Option<Uuid>,
140}
141
142impl SignalWebSocket<websocket::Identified> {
143 pub async fn whoami(&mut self) -> Result<WhoAmIResponse, ServiceError> {
145 self.http_request(Method::GET, "/v1/accounts/whoami")?
146 .send()
147 .await?
148 .service_error_for_status()
149 .await?
150 .json()
151 .await
152 }
153
154 pub(crate) async fn devices(
158 &mut self,
159 ) -> Result<Vec<DeviceInfoEncrypted>, ServiceError> {
160 #[derive(serde::Deserialize)]
161 struct DeviceInfoList {
162 devices: Vec<DeviceInfoEncrypted>,
163 }
164
165 let devices: DeviceInfoList = self
166 .http_request(Method::GET, "/v1/devices")?
167 .send()
168 .await?
169 .service_error_for_status()
170 .await?
171 .json()
172 .await?;
173
174 Ok(devices.devices)
175 }
176
177 pub async fn set_account_attributes(
178 &mut self,
179 attributes: AccountAttributes,
180 ) -> Result<(), ServiceError> {
181 self.http_request(Method::PUT, "/v1/accounts/attributes")?
182 .send_json(&attributes)
183 .await?
184 .service_error_for_status()
185 .await?;
186
187 Ok(())
188 }
189
190 pub async fn unregister_account(&mut self) -> Result<(), ServiceError> {
197 self.http_request(Method::DELETE, "/v1/accounts/me")?
198 .send()
199 .await?
200 .service_error_for_status()
201 .await?;
202
203 Ok(())
204 }
205}