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, utils::serde_optional_base64,
9    utils::serde_phone_number, websocket,
10};
11
12use super::SignalWebSocket;
13
14#[derive(Debug, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct DeviceId {
17    pub device_id: u32,
18}
19
20#[derive(Debug, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct DeviceInfo {
23    pub id: u8,
24    pub name: Option<String>,
25    #[serde(with = "chrono::serde::ts_milliseconds")]
26    pub created: DateTime<Utc>,
27    #[serde(with = "chrono::serde::ts_milliseconds")]
28    pub last_seen: DateTime<Utc>,
29}
30
31#[derive(Debug, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct AccountAttributes {
34    #[serde(default, with = "serde_optional_base64")]
35    pub signaling_key: Option<Vec<u8>>,
36    pub registration_id: u32,
37    pub pni_registration_id: u32,
38    pub voice: bool,
39    pub video: bool,
40    pub fetches_messages: bool,
41    pub pin: Option<String>,
42    pub registration_lock: Option<String>,
43    #[serde(default, with = "serde_optional_base64")]
44    pub unidentified_access_key: Option<Vec<u8>>,
45    pub unrestricted_unidentified_access: bool,
46    pub discoverable_by_phone_number: bool,
47    pub capabilities: DeviceCapabilities,
48    pub name: Option<String>,
49}
50
51#[derive(Debug, Serialize, Deserialize, Default, Eq, PartialEq, Clone)]
52#[serde(rename_all = "camelCase")]
53pub struct DeviceCapabilities {
54    #[serde(default)]
55    pub storage: bool,
56    #[serde(default)]
57    pub sender_key: bool,
58    #[serde(default)]
59    pub announcement_group: bool,
60    #[serde(default)]
61    pub change_number: bool,
62    #[serde(default)]
63    pub stories: bool,
64    #[serde(default)]
65    pub gift_badges: bool,
66    #[serde(default)]
67    pub pni: bool,
68    #[serde(default)]
69    pub payment_activation: bool,
70}
71
72#[derive(Debug, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct WhoAmIResponse {
75    #[serde(rename = "uuid")]
76    pub aci: Uuid,
77    #[serde(default)] // nil when not present (yet)
78    pub pni: Uuid,
79    #[serde(with = "serde_phone_number")]
80    pub number: PhoneNumber,
81}
82
83impl SignalWebSocket<websocket::Identified> {
84    /// Method used to check our own UUID
85    pub async fn whoami(&mut self) -> Result<WhoAmIResponse, ServiceError> {
86        self.http_request(Method::GET, "/v1/accounts/whoami")?
87            .send()
88            .await?
89            .service_error_for_status()
90            .await?
91            .json()
92            .await
93    }
94
95    /// Fetches a list of all devices tied to the authenticated account.
96    ///
97    /// This list include the device that sends the request.
98    pub async fn devices(&mut self) -> Result<Vec<DeviceInfo>, ServiceError> {
99        #[derive(serde::Deserialize)]
100        struct DeviceInfoList {
101            devices: Vec<DeviceInfo>,
102        }
103
104        let devices: DeviceInfoList = self
105            .http_request(Method::GET, "/v1/devices")?
106            .send()
107            .await?
108            .service_error_for_status()
109            .await?
110            .json()
111            .await?;
112
113        Ok(devices.devices)
114    }
115
116    pub async fn set_account_attributes(
117        &mut self,
118        attributes: AccountAttributes,
119    ) -> Result<(), ServiceError> {
120        assert!(
121            attributes.pin.is_none() || attributes.registration_lock.is_none(),
122            "only one of PIN and registration lock can be set."
123        );
124
125        self.http_request(Method::PUT, "/v1/accounts/attributes")?
126            .send_json(&attributes)
127            .await?
128            .service_error_for_status()
129            .await?
130            .json()
131            .await
132    }
133}