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