Skip to main content

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}