libsignal_service/push_service/
linking.rs

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5use crate::configuration::Endpoint;
6
7use super::{
8    response::ReqwestExt, DeviceActivationRequest, HttpAuth, HttpAuthOverride,
9    PushService, ServiceError,
10};
11
12#[derive(Debug, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct LinkAccountAttributes {
15    pub fetches_messages: bool,
16    pub name: String,
17    pub registration_id: u32,
18    pub pni_registration_id: u32,
19    pub capabilities: LinkCapabilities,
20}
21
22#[derive(Debug, Serialize)]
23#[serde(rename_all = "camelCase")]
24pub struct LinkCapabilities {
25    pub delete_sync: bool,
26    pub versioned_expiration_timer: bool,
27    /// It is currently unclear what this field is.
28    ///
29    /// Signal Server refers to the field as `STORAGE_SERVICE_RECORD_KEY_ROTATION` [here](https://github.com/signalapp/Signal-Server/blob/5cc76f48aa4028f5001a51409a3a0e4e6ce2d7f2/service/src/main/java/org/whispersystems/textsecuregcm/storage/DeviceCapability.java#L15).
30    /// Signal Android refers to the field as `storageServiceEncryptionV2` [here](https://github.com/signalapp/Signal-Android/blob/ec840726fcbb5440e1337274f791d17a6fe59598/libsignal-service/src/main/java/org/whispersystems/signalservice/api/account/AccountAttributes.kt#L60).
31    /// It is therefore possibly related to backup
32    pub ssre2: bool,
33}
34
35// https://github.com/signalapp/Signal-Desktop/blob/1e57db6aa4786dcddc944349e4894333ac2ffc9e/ts/textsecure/WebAPI.ts#L1287
36impl Default for LinkCapabilities {
37    fn default() -> Self {
38        Self {
39            delete_sync: true,
40            versioned_expiration_timer: true,
41            ssre2: true,
42        }
43    }
44}
45
46#[derive(Debug, Deserialize)]
47#[serde(rename_all = "camelCase")]
48pub struct LinkResponse {
49    #[serde(rename = "uuid")]
50    pub aci: Uuid,
51    pub pni: Uuid,
52    pub device_id: u32,
53}
54
55#[derive(Debug, Serialize)]
56#[serde(rename_all = "camelCase")]
57pub struct LinkRequest {
58    pub verification_code: String,
59    pub account_attributes: LinkAccountAttributes,
60    #[serde(flatten)]
61    pub device_activation_request: DeviceActivationRequest,
62}
63
64impl PushService {
65    pub async fn link_device(
66        &mut self,
67        link_request: &LinkRequest,
68        http_auth: HttpAuth,
69    ) -> Result<LinkResponse, ServiceError> {
70        self.request(
71            Method::PUT,
72            Endpoint::service("/v1/devices/link"),
73            HttpAuthOverride::Identified(http_auth),
74        )?
75        .json(&link_request)
76        .send()
77        .await?
78        .service_error_for_status()
79        .await?
80        .json()
81        .await
82        .map_err(Into::into)
83    }
84
85    pub async fn unlink_device(&mut self, id: i64) -> Result<(), ServiceError> {
86        self.request(
87            Method::DELETE,
88            Endpoint::service(format!("/v1/devices/{}", id)),
89            HttpAuthOverride::NoOverride,
90        )?
91        .send()
92        .await?
93        .service_error_for_status()
94        .await?;
95
96        Ok(())
97    }
98}