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}