libsignal_service/
proto.rs

1#![allow(clippy::all)]
2
3use rand::{CryptoRng, Rng};
4use reqwest::StatusCode;
5include!(concat!(env!("OUT_DIR"), "/signalservice.rs"));
6include!(concat!(env!("OUT_DIR"), "/signal.rs"));
7
8impl WebSocketRequestMessage {
9    /// Equivalent of
10    /// `SignalServiceMessagePipe::isSignalServiceEnvelope(WebSocketMessage)`.
11    pub fn is_signal_service_envelope(&self) -> bool {
12        self.verb.as_deref() == Some("PUT")
13            && self.path.as_deref() == Some("/api/v1/message")
14    }
15
16    pub fn is_queue_empty(&self) -> bool {
17        self.verb.as_deref() == Some("PUT")
18            && self.path.as_deref() == Some("/api/v1/queue/empty")
19    }
20
21    /// Equivalent of
22    /// `SignalServiceMessagePipe::isSignalKeyEncrypted(WebSocketMessage)`.
23    pub fn is_signal_key_encrypted(&self) -> bool {
24        if self.headers.is_empty() {
25            return true;
26        }
27
28        for header in &self.headers {
29            let parts: Vec<_> = header.split(':').collect();
30            if parts.len() != 2 {
31                tracing::warn!(
32                    "Got a weird header: {:?}, split in {:?}",
33                    header,
34                    parts
35                );
36                continue;
37            }
38
39            if parts[0].trim().eq_ignore_ascii_case("X-Signal-Key")
40                && parts[1].trim().eq_ignore_ascii_case("false")
41            {
42                return false;
43            }
44        }
45
46        true
47    }
48}
49
50impl WebSocketResponseMessage {
51    /// Equivalent of
52    /// `SignalServiceMessagePipe::isSignalServiceEnvelope(WebSocketMessage)`.
53    pub fn from_request(msg: &WebSocketRequestMessage) -> Self {
54        if msg.is_signal_service_envelope() || msg.is_queue_empty() {
55            WebSocketResponseMessage {
56                id: msg.id,
57                status: Some(200),
58                message: Some("OK".to_string()),
59                ..Default::default()
60            }
61        } else {
62            WebSocketResponseMessage {
63                id: msg.id,
64                status: Some(400),
65                message: Some("Unknown".to_string()),
66                ..Default::default()
67            }
68        }
69    }
70
71    pub fn status_code(&self) -> Option<reqwest::StatusCode> {
72        StatusCode::from_u16(self.status().try_into().ok()?).ok()
73    }
74}
75
76impl SyncMessage {
77    pub fn with_padding<R: Rng + CryptoRng>(csprng: &mut R) -> Self {
78        let random_size = csprng.random_range(1..=512);
79        let mut padding: Vec<u8> = vec![0; random_size];
80        csprng.fill_bytes(&mut padding);
81
82        Self {
83            padding: Some(padding),
84            ..Default::default()
85        }
86    }
87}