libsignal_service/websocket/
account.rs1use chrono::{DateTime, Utc};
2use phonenumber::PhoneNumber;
3use reqwest::Method;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::{
8 content::ServiceError,
9 utils::serde_optional_base64,
10 utils::{serde_device_id, serde_phone_number},
11 websocket,
12};
13
14use super::SignalWebSocket;
15
16#[derive(Debug, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct DeviceId {
19 #[serde(with = "serde_device_id")]
20 pub device_id: libsignal_core::DeviceId,
21}
22
23#[derive(Debug, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct DeviceInfo {
26 #[serde(with = "serde_device_id")]
27 pub id: libsignal_core::DeviceId,
28 pub registration_id: i32,
29 pub name: Option<String>,
30 #[serde(with = "chrono::serde::ts_milliseconds")]
31 pub created_at: DateTime<Utc>,
32 #[serde(with = "chrono::serde::ts_milliseconds")]
33 pub last_seen: DateTime<Utc>,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub(crate) struct DeviceInfoEncrypted {
39 #[serde(with = "serde_device_id")]
40 pub id: libsignal_core::DeviceId,
41 pub name: Option<String>,
42 pub registration_id: i32,
43 pub created_at_ciphertext: String,
44 #[serde(with = "chrono::serde::ts_milliseconds")]
45 pub last_seen: DateTime<Utc>,
46}
47
48#[derive(Debug, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct AccountAttributes {
51 #[serde(default, with = "serde_optional_base64")]
52 pub signaling_key: Option<Vec<u8>>,
53 pub registration_id: u32,
54 pub pni_registration_id: u32,
55 pub voice: bool,
56 pub video: bool,
57 pub fetches_messages: bool,
58 pub pin: Option<String>,
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 pub capabilities: DeviceCapabilities,
65 pub name: Option<String>,
66}
67
68#[derive(Debug, Serialize, Deserialize, Default, Eq, PartialEq, Clone)]
69#[serde(rename_all = "camelCase")]
70pub struct DeviceCapabilities {
71 #[serde(default)]
72 pub storage: bool,
73 #[serde(default)]
74 pub sender_key: bool,
75 #[serde(default)]
76 pub announcement_group: bool,
77 #[serde(default)]
78 pub change_number: bool,
79 #[serde(default)]
80 pub stories: bool,
81 #[serde(default)]
82 pub gift_badges: bool,
83 #[serde(default)]
84 pub pni: bool,
85 #[serde(default)]
86 pub payment_activation: bool,
87}
88
89#[derive(Debug, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct WhoAmIResponse {
92 #[serde(rename = "uuid")]
93 pub aci: Uuid,
94 #[serde(default)] pub pni: Uuid,
96 #[serde(with = "serde_phone_number")]
97 pub number: PhoneNumber,
98}
99
100impl SignalWebSocket<websocket::Identified> {
101 pub async fn whoami(&mut self) -> Result<WhoAmIResponse, ServiceError> {
103 self.http_request(Method::GET, "/v1/accounts/whoami")?
104 .send()
105 .await?
106 .service_error_for_status()
107 .await?
108 .json()
109 .await
110 }
111
112 pub(crate) async fn devices(
116 &mut self,
117 ) -> Result<Vec<DeviceInfoEncrypted>, ServiceError> {
118 #[derive(serde::Deserialize)]
119 struct DeviceInfoList {
120 devices: Vec<DeviceInfoEncrypted>,
121 }
122
123 let devices: DeviceInfoList = self
124 .http_request(Method::GET, "/v1/devices")?
125 .send()
126 .await?
127 .service_error_for_status()
128 .await?
129 .json()
130 .await?;
131
132 Ok(devices.devices)
133 }
134
135 pub async fn set_account_attributes(
136 &mut self,
137 attributes: AccountAttributes,
138 ) -> Result<(), ServiceError> {
139 assert!(
140 attributes.pin.is_none() || attributes.registration_lock.is_none(),
141 "only one of PIN and registration lock can be set."
142 );
143
144 self.http_request(Method::PUT, "/v1/accounts/attributes")?
145 .send_json(&attributes)
146 .await?
147 .service_error_for_status()
148 .await?;
149
150 Ok(())
151 }
152}