bitwarden_ipc/traits/crypto_provider.rs
1use std::fmt::Debug;
2
3#[cfg(any(test, feature = "test-support"))]
4use super::CommunicationBackendReceiver;
5use super::{CommunicationBackend, SessionRepository};
6use crate::{
7 error::IpcErrorKind,
8 message::{IncomingMessage, OutgoingMessage},
9};
10
11pub trait CryptoProvider<Com, Ses>: Send + Sync + 'static
12where
13 Com: CommunicationBackend,
14 Ses: SessionRepository<Self::Session>,
15{
16 type Session: Send + Sync + 'static;
17 type SendError: Debug + Send + Sync + 'static + IpcErrorKind;
18 type ReceiveError: Debug + Send + Sync + 'static + IpcErrorKind;
19
20 /// Largest payload [`send`](Self::send) accepts in a single message. The IPC client fragments
21 /// larger payloads into messages of at most this size.
22 fn max_payload_len(&self) -> usize;
23
24 /// Send a message.
25 ///
26 /// Calling this function may result in multiple messages being sent, depending on the
27 /// implementation of the trait. For example, if the destination does not have a
28 /// session, the function may first send a message to establish a session and then send the
29 /// original message. The implementation of this function should handle this logic.
30 ///
31 /// Both recoverable and fatal errors may be returned, classified via
32 /// [`IpcErrorKind::kind()`]. A recoverable error (e.g. a handshake timeout or a transient
33 /// transport failure) is logged and the IPC client keeps running; a fatal error (e.g. the
34 /// session storage being inaccessible) stops the client from processing any further messages.
35 /// Ambiguous cases should be classified as recoverable.
36 fn send(
37 &self,
38 communication: &Com,
39 sessions: &Ses,
40 message: OutgoingMessage,
41 ) -> impl std::future::Future<Output = Result<(), Self::SendError>> + Send + Sync;
42
43 /// Receive a message.
44 ///
45 /// Calling this function may also result in messages being sent, depending on the trait
46 /// implementation. For example, if an encrypted message is received from a destination that
47 /// does not have a session. The function may then try to establish a session and then
48 /// re-request the original message. The implementation of this function should handle this
49 /// logic.
50 ///
51 /// Both recoverable and fatal errors may be returned, classified via
52 /// [`IpcErrorKind::kind()`]. A recoverable error (e.g. a malformed frame from one peer or a
53 /// transient transport failure) is logged and the IPC client's processing loop continues; a
54 /// fatal error (e.g. the session storage being inaccessible) stops the loop. Ambiguous cases
55 /// should be classified as recoverable.
56 fn receive(
57 &self,
58 receiver: &Com::Receiver,
59 communication: &Com,
60 sessions: &Ses,
61 ) -> impl std::future::Future<Output = Result<IncomingMessage, Self::ReceiveError>> + Send + Sync;
62}
63
64/// A no-op crypto provider that performs no encryption and simply passes messages through as-is.
65#[cfg(any(test, feature = "test-support"))]
66pub struct NoEncryptionCryptoProvider;
67
68#[cfg(any(test, feature = "test-support"))]
69impl<Com, Ses> CryptoProvider<Com, Ses> for NoEncryptionCryptoProvider
70where
71 Com: CommunicationBackend,
72 Ses: SessionRepository<()>,
73{
74 type Session = ();
75 type SendError = Com::SendError;
76 type ReceiveError = <Com::Receiver as CommunicationBackendReceiver>::ReceiveError;
77
78 fn max_payload_len(&self) -> usize {
79 usize::MAX
80 }
81
82 async fn send(
83 &self,
84 communication: &Com,
85 _sessions: &Ses,
86 message: OutgoingMessage,
87 ) -> Result<(), Self::SendError> {
88 communication.send(message).await
89 }
90
91 async fn receive(
92 &self,
93 receiver: &Com::Receiver,
94 _communication: &Com,
95 _sessions: &Ses,
96 ) -> Result<IncomingMessage, Self::ReceiveError> {
97 receiver.receive().await
98 }
99}