libsignal_service/push_service/
linking.rs

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