libsignal_service/websocket/
account.rs

1use 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)] // nil when not present (yet)
95    pub pni: Uuid,
96    #[serde(with = "serde_phone_number")]
97    pub number: PhoneNumber,
98}
99
100impl SignalWebSocket<websocket::Identified> {
101    /// Method used to check our own UUID
102    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    /// Fetches a list of all devices tied to the authenticated account.
113    ///
114    /// This list include the device that sends the request.
115    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}