libsignal_service/websocket/
keys.rs1use std::collections::HashMap;
2
3use libsignal_protocol::{
4 kem::{Key, Public},
5 IdentityKey, PreKeyBundle, PublicKey, SenderCertificate, ServiceId,
6 ServiceIdKind, SignalProtocolError,
7};
8use reqwest::Method;
9use serde::Deserialize;
10
11use crate::{
12 pre_keys::{
13 KyberPreKeyEntity, PreKeyEntity, PreKeyState, SignedPreKeyEntity,
14 },
15 sender::OutgoingPushMessage,
16 utils::serde_base64,
17 websocket::{self, registration::VerifyAccountResponse, SignalWebSocket},
18};
19
20use super::ServiceError;
21
22#[derive(Debug, Deserialize, Default)]
23#[serde(rename_all = "camelCase")]
24pub struct PreKeyStatus {
25 pub count: u32,
26 pub pq_count: u32,
27}
28
29#[derive(Debug, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub struct PreKeyResponse {
32 #[serde(with = "serde_base64")]
33 pub identity_key: Vec<u8>,
34 pub devices: Vec<PreKeyResponseItem>,
35}
36
37#[derive(Debug, Deserialize)]
38#[serde(rename_all = "camelCase")]
39pub struct PreKeyResponseItem {
40 pub device_id: u32,
41 pub registration_id: u32,
42 pub signed_pre_key: SignedPreKeyEntity,
43 pub pre_key: Option<PreKeyEntity>,
44 pub pq_pre_key: KyberPreKeyEntity,
45}
46
47impl PreKeyResponseItem {
48 pub(crate) fn into_bundle(
49 self,
50 identity: IdentityKey,
51 ) -> Result<PreKeyBundle, ServiceError> {
52 let device_id = self.device_id.try_into()?;
53 let pre_key_bundle = PreKeyBundle::new(
54 self.registration_id,
55 device_id,
56 self.pre_key
57 .map(|pk| -> Result<_, SignalProtocolError> {
58 Ok((
59 pk.key_id.into(),
60 PublicKey::deserialize(&pk.public_key)?,
61 ))
62 })
63 .transpose()?,
64 self.signed_pre_key.key_id.into(),
66 PublicKey::deserialize(&self.signed_pre_key.public_key)?,
67 self.signed_pre_key.signature,
68 self.pq_pre_key.key_id.into(),
69 Key::<Public>::deserialize(&self.pq_pre_key.public_key)?,
70 self.pq_pre_key.signature,
71 identity,
72 )?;
73
74 Ok(pre_key_bundle)
75 }
76}
77
78#[derive(Debug, Deserialize)]
79#[serde(rename_all = "camelCase")]
80struct SenderCertificateJson {
81 #[serde(with = "serde_base64")]
82 certificate: Vec<u8>,
83}
84
85impl SignalWebSocket<websocket::Identified> {
86 pub async fn get_pre_key_status(
87 &mut self,
88 service_id_kind: ServiceIdKind,
89 ) -> Result<PreKeyStatus, ServiceError> {
90 self.http_request(
91 Method::GET,
92 format!("/v2/keys?identity={}", service_id_kind),
93 )?
94 .send()
95 .await?
96 .service_error_for_status()
97 .await?
98 .json()
99 .await
100 }
101
102 pub async fn check_pre_keys(
112 &mut self,
113 service_id_kind: ServiceIdKind,
114 digest: &[u8; 32],
115 ) -> Result<bool, ServiceError> {
116 #[derive(serde::Serialize)]
117 #[serde(rename_all = "camelCase")]
118 struct CheckPreKeysRequest<'a> {
119 identity_type: String,
120 #[serde(with = "serde_base64")]
121 digest: &'a [u8; 32],
122 }
123
124 let req = CheckPreKeysRequest {
125 identity_type: service_id_kind.to_string(),
126 digest,
127 };
128
129 let res = self
130 .http_request(Method::POST, "/v2/keys/check")?
131 .send_json(&req)
132 .await?;
133
134 if res.status_code() == Some(reqwest::StatusCode::CONFLICT) {
135 return Ok(false);
136 }
137
138 res.service_error_for_status().await?;
139
140 Ok(true)
141 }
142
143 pub async fn register_pre_keys(
144 &mut self,
145 service_id_kind: ServiceIdKind,
146 pre_key_state: PreKeyState,
147 ) -> Result<(), ServiceError> {
148 self.http_request(
149 Method::PUT,
150 format!("/v2/keys?identity={}", service_id_kind),
151 )?
152 .send_json(&pre_key_state)
153 .await?
154 .service_error_for_status()
155 .await?;
156
157 Ok(())
158 }
159
160 pub async fn get_pre_key(
161 &mut self,
162 destination: &ServiceId,
163 device_id: u32,
164 ) -> Result<PreKeyBundle, ServiceError> {
165 let path = format!(
166 "/v2/keys/{}/{}",
167 destination.service_id_string(),
168 device_id
169 );
170
171 let mut pre_key_response: PreKeyResponse = self
172 .http_request(Method::GET, path)?
173 .send()
174 .await?
175 .service_error_for_status()
176 .await?
177 .json()
178 .await?;
179
180 assert!(!pre_key_response.devices.is_empty());
181
182 let identity = IdentityKey::decode(&pre_key_response.identity_key)?;
183 let device = pre_key_response.devices.remove(0);
184 device.into_bundle(identity)
185 }
186
187 pub(crate) async fn get_pre_keys(
188 &mut self,
189 destination: &ServiceId,
190 device_id: u32,
191 ) -> Result<Vec<PreKeyBundle>, ServiceError> {
192 let path = if device_id == 1 {
193 format!("/v2/keys/{}/*", destination.service_id_string())
194 } else {
195 format!(
196 "/v2/keys/{}/{}",
197 destination.service_id_string(),
198 device_id
199 )
200 };
201 let pre_key_response: PreKeyResponse = self
202 .http_request(Method::GET, path)?
203 .send()
204 .await?
205 .service_error_for_status()
206 .await?
207 .json()
208 .await?;
209 let mut pre_keys = vec![];
210 let identity = IdentityKey::decode(&pre_key_response.identity_key)?;
211 for device in pre_key_response.devices {
212 pre_keys.push(device.into_bundle(identity)?);
213 }
214 Ok(pre_keys)
215 }
216
217 pub async fn get_sender_certificate(
218 &mut self,
219 ) -> Result<SenderCertificate, ServiceError> {
220 let cert: SenderCertificateJson = self
221 .http_request(Method::GET, "/v1/certificate/delivery")?
222 .send()
223 .await?
224 .service_error_for_status()
225 .await?
226 .json()
227 .await?;
228 Ok(SenderCertificate::deserialize(&cert.certificate)?)
229 }
230
231 pub async fn get_uuid_only_sender_certificate(
232 &mut self,
233 ) -> Result<SenderCertificate, ServiceError> {
234 let cert: SenderCertificateJson = self
235 .http_request(
236 Method::GET,
237 "/v1/certificate/delivery?includeE164=false",
238 )?
239 .send()
240 .await?
241 .service_error_for_status()
242 .await?
243 .json()
244 .await?;
245 Ok(SenderCertificate::deserialize(&cert.certificate)?)
246 }
247
248 pub async fn distribute_pni_keys(
249 &mut self,
250 pni_identity_key: &IdentityKey,
251 device_messages: Vec<OutgoingPushMessage>,
252 device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
253 device_pni_last_resort_kyber_prekeys: HashMap<
254 String,
255 KyberPreKeyEntity,
256 >,
257 pni_registration_ids: HashMap<String, u32>,
258 signature_valid_on_each_signed_pre_key: bool,
259 ) -> Result<VerifyAccountResponse, ServiceError> {
260 #[derive(serde::Serialize, Debug)]
261 #[serde(rename_all = "camelCase")]
262 struct PniKeyDistributionRequest {
263 #[serde(with = "serde_base64")]
264 pni_identity_key: Vec<u8>,
265 device_messages: Vec<OutgoingPushMessage>,
266 device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
267 #[serde(rename = "devicePniPqLastResortPrekeys")]
268 device_pni_last_resort_kyber_prekeys:
269 HashMap<String, KyberPreKeyEntity>,
270 pni_registration_ids: HashMap<String, u32>,
271 signature_valid_on_each_signed_pre_key: bool,
272 }
273 self.http_request(
274 Method::PUT,
275 "/v2/accounts/phone_number_identity_key_distribution",
276 )?
277 .send_json(&PniKeyDistributionRequest {
278 pni_identity_key: pni_identity_key.serialize().into(),
279 device_messages,
280 device_pni_signed_prekeys,
281 device_pni_last_resort_kyber_prekeys,
282 pni_registration_ids,
283 signature_valid_on_each_signed_pre_key,
284 })
285 .await?
286 .service_error_for_status()
287 .await?
288 .json()
289 .await
290 }
291}