libsignal_service/push_service/
linking.rs

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5use crate::{
6    configuration::Endpoint, websocket::registration::DeviceActivationRequest,
7};
8
9use super::{
10    response::ReqwestExt, HttpAuth, HttpAuthOverride, PushService, ServiceError,
11};
12
13#[derive(Debug, Serialize)]
14#[serde(rename_all = "camelCase")]
15pub struct LinkAccountAttributes {
16    pub fetches_messages: bool,
17    pub name: String,
18    pub registration_id: u32,
19    pub pni_registration_id: u32,
20    pub capabilities: LinkCapabilities,
21}
22
23#[derive(Debug, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct LinkCapabilities {
26    pub delete_sync: bool,
27    pub versioned_expiration_timer: bool,
28    /// It is currently unclear what this field is.
29    ///
30    /// 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).
31    /// 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).
32    /// It is therefore possibly related to backup
33    pub ssre2: bool,
34}
35
36// https://github.com/signalapp/Signal-Desktop/blob/1e57db6aa4786dcddc944349e4894333ac2ffc9e/ts/textsecure/WebAPI.ts#L1287
37impl Default for LinkCapabilities {
38    fn default() -> Self {
39        Self {
40            delete_sync: true,
41            versioned_expiration_timer: true,
42            ssre2: true,
43        }
44    }
45}
46
47#[derive(Debug, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct LinkResponse {
50    #[serde(rename = "uuid")]
51    pub aci: Uuid,
52    pub pni: Uuid,
53    pub device_id: u32,
54}
55
56#[derive(Debug, Serialize)]
57#[serde(rename_all = "camelCase")]
58pub struct LinkRequest {
59    pub verification_code: String,
60    pub account_attributes: LinkAccountAttributes,
61    #[serde(flatten)]
62    pub device_activation_request: DeviceActivationRequest,
63}
64
65impl PushService {
66    pub async fn link_device(
67        &mut self,
68        link_request: &LinkRequest,
69        http_auth: HttpAuth,
70    ) -> Result<LinkResponse, ServiceError> {
71        self.request(
72            Method::PUT,
73            Endpoint::service("/v1/devices/link"),
74            HttpAuthOverride::Identified(http_auth),
75        )?
76        .json(&link_request)
77        .send()
78        .await?
79        .service_error_for_status()
80        .await?
81        .json()
82        .await
83        .map_err(Into::into)
84    }
85}