whatsapp_rust/socket/
error.rs1use thiserror::Error;
2use wacore::handshake::NoiseError;
3use wacore_binary::error::BinaryError;
4
5#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum SocketError {
8 #[error("socket is closed")]
9 SocketClosed,
10 #[error("I/O error")]
11 Io(#[from] std::io::Error),
12 #[error("noise cipher operation failed")]
13 Cipher(#[from] NoiseError),
14 #[error("binary protocol marshalling failed")]
15 Marshal(#[source] BinaryError),
16}
17
18pub type Result<T> = std::result::Result<T, SocketError>;
19
20pub type EncryptSendResult = std::result::Result<(), EncryptSendError>;
22
23#[derive(Debug, thiserror::Error)]
24#[non_exhaustive]
25pub enum EncryptSendErrorKind {
26 #[error("cryptography error")]
27 Crypto,
28 #[error("framing error")]
29 Framing,
30 #[error("transport error")]
31 Transport,
32 #[error("task join error")]
33 Join,
34 #[error("sender channel closed")]
35 ChannelClosed,
36 #[error("sender poisoned by an earlier transport failure")]
40 Poisoned,
41}
42
43#[derive(Debug, thiserror::Error)]
44#[error("{kind}")]
45#[non_exhaustive]
46pub struct EncryptSendError {
47 pub kind: EncryptSendErrorKind,
48 #[source]
49 pub source: anyhow::Error,
50}
51
52impl EncryptSendError {
53 pub fn crypto(source: impl Into<anyhow::Error>) -> Self {
54 Self {
55 kind: EncryptSendErrorKind::Crypto,
56 source: source.into(),
57 }
58 }
59
60 pub fn framing(source: impl Into<anyhow::Error>) -> Self {
61 Self {
62 kind: EncryptSendErrorKind::Framing,
63 source: source.into(),
64 }
65 }
66
67 pub fn transport(source: impl Into<anyhow::Error>) -> Self {
68 Self {
69 kind: EncryptSendErrorKind::Transport,
70 source: source.into(),
71 }
72 }
73
74 pub fn join(source: impl Into<anyhow::Error>) -> Self {
75 Self {
76 kind: EncryptSendErrorKind::Join,
77 source: source.into(),
78 }
79 }
80
81 pub fn channel_closed() -> Self {
82 Self {
83 kind: EncryptSendErrorKind::ChannelClosed,
84 source: anyhow::anyhow!("sender task channel closed unexpectedly"),
85 }
86 }
87
88 pub fn poisoned() -> Self {
96 Self {
97 kind: EncryptSendErrorKind::Poisoned,
98 source: anyhow::anyhow!(
99 "noise sender disabled after a transport failure; reconnect to rekey"
100 ),
101 }
102 }
103
104 pub fn is_transport_unavailable(&self) -> bool {
108 matches!(
109 self.kind,
110 EncryptSendErrorKind::Transport
111 | EncryptSendErrorKind::ChannelClosed
112 | EncryptSendErrorKind::Poisoned
113 )
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use wacore::libsignal::crypto::CryptoProviderError;
121
122 #[test]
123 fn cipher_preserves_noise_source_through_socket_error() {
124 let noise = NoiseError::Decrypt(CryptoProviderError::AuthFailed);
125 let se: SocketError = noise.into();
126 let src = std::error::Error::source(&se).expect("source preserved");
128 let ne = src
129 .downcast_ref::<NoiseError>()
130 .expect("downcasts to NoiseError");
131 assert!(matches!(ne, NoiseError::Decrypt(_)));
132 let inner = std::error::Error::source(ne).expect("inner source preserved");
134 let cpe = inner
135 .downcast_ref::<CryptoProviderError>()
136 .expect("downcasts to CryptoProviderError");
137 assert!(matches!(cpe, CryptoProviderError::AuthFailed));
138 }
139
140 #[test]
141 fn crypto_preserves_the_noise_error_type() {
142 let err = EncryptSendError::crypto(NoiseError::Encrypt(CryptoProviderError::BackendFailed));
143 assert!(matches!(err.kind, EncryptSendErrorKind::Crypto));
144 let src = std::error::Error::source(&err).expect("source preserved");
145 let ne = src
146 .downcast_ref::<NoiseError>()
147 .expect("downcasts to NoiseError");
148 assert!(matches!(ne, NoiseError::Encrypt(_)));
149 }
150
151 #[test]
152 fn crypto_from_an_untyped_source_still_carries_its_message() {
153 let err = EncryptSendError::crypto(anyhow::anyhow!("some opaque failure"));
154 let src = std::error::Error::source(&err).expect("source preserved");
155 assert!(src.downcast_ref::<NoiseError>().is_none());
156 assert_eq!(src.to_string(), "some opaque failure");
157 }
158
159 #[test]
160 fn marshal_preserves_binary_error_source() {
161 let be = BinaryError::InvalidNode;
162 let se = SocketError::Marshal(be);
163 let src = std::error::Error::source(&se).expect("source preserved");
164 let inner = src
165 .downcast_ref::<BinaryError>()
166 .expect("downcasts to BinaryError");
167 assert!(matches!(inner, BinaryError::InvalidNode));
168 }
169}