Skip to main content

kevy_embedded/
config_secure.rs

1//! Keys for encrypting an embed's replication links with Noise IK. Both
2//! directions stay plaintext unless one of these is configured.
3
4use crate::config::Config;
5
6pub use kevy_noise::Keypair;
7
8/// One end's key pair, and the public keys of the other ends it accepts.
9///
10/// ```
11/// use kevy_embedded::{Keypair, LinkKeys};
12///
13/// let keys = LinkKeys::new(Keypair::from_secret([1; 32])).with_peers(vec![[2; 32]]);
14/// assert_eq!(keys.peers.len(), 1);
15/// ```
16#[derive(Debug, Clone)]
17#[non_exhaustive]
18pub struct LinkKeys {
19    /// This store's static key pair.
20    ///
21    /// ```
22    /// let keys = kevy_embedded::LinkKeys::new(kevy_embedded::Keypair::from_secret([1; 32]));
23    /// assert_ne!(keys.local.public(), [0; 32]);
24    /// ```
25    pub local: Keypair,
26    /// On a replica, the primary keys it trusts, tried in turn until one
27    /// answers; it needs at least one. On a writer, the replica keys it
28    /// accepts; empty accepts any replica, still encrypted.
29    ///
30    /// ```
31    /// let primary = kevy_embedded::Keypair::from_secret([2; 32]);
32    /// let keys = kevy_embedded::LinkKeys::new(kevy_embedded::Keypair::from_secret([1; 32]))
33    ///     .with_peers(vec![primary.public()]);
34    /// assert_eq!(keys.peers[0], primary.public());
35    /// ```
36    pub peers: Vec<[u8; 32]>,
37}
38
39impl LinkKeys {
40    /// This end's key pair `local`, with no peers yet. The key has no
41    /// default: without it the link authenticates nobody.
42    ///
43    /// ```
44    /// let keys = kevy_embedded::LinkKeys::new(kevy_embedded::Keypair::from_secret([1; 32]));
45    /// assert!(keys.peers.is_empty());
46    /// ```
47    #[must_use]
48    pub fn new(local: Keypair) -> Self {
49        Self { local, peers: Vec::new() }
50    }
51
52    /// Set [`Self::peers`].
53    ///
54    /// ```
55    /// let keys = kevy_embedded::LinkKeys::new(kevy_embedded::Keypair::from_secret([1; 32]))
56    ///     .with_peers(vec![[2; 32], [3; 32]]);
57    /// assert_eq!(keys.peers.len(), 2);
58    /// ```
59    #[must_use]
60    pub fn with_peers(mut self, peers: Vec<[u8; 32]>) -> Self {
61        self.peers = peers;
62        self
63    }
64}
65
66/// The keys for each replication direction; `None` keeps it plaintext.
67#[derive(Debug, Clone, Default)]
68pub(crate) struct LinkSecurity {
69    pub(crate) replica: Option<LinkKeys>,
70    pub(crate) writer: Option<LinkKeys>,
71}
72
73impl Config {
74    /// Encrypt the link to the replication upstream: the replica presents
75    /// `keys.local` and connects only to a primary holding one of
76    /// `keys.peers`. Opening fails when `keys.peers` is empty.
77    ///
78    /// ```
79    /// use kevy_embedded::{Config, Keypair, LinkKeys, Store};
80    ///
81    /// let primary = Keypair::from_secret([2; 32]);
82    /// let replica = |peers| {
83    ///     Config::default()
84    ///         .without_aof()
85    ///         .with_replica_upstream("127.0.0.1:16004")
86    ///         .with_replica_security(LinkKeys::new(Keypair::from_secret([1; 32])).with_peers(peers))
87    /// };
88    /// assert!(Store::open(replica(vec![primary.public()]))?.is_replica());
89    /// // a secure replica that trusts no primary does not open
90    /// assert!(Store::open(replica(vec![])).is_err());
91    /// # Ok::<(), kevy_embedded::KevyError>(())
92    /// ```
93    #[must_use]
94    pub fn with_replica_security(mut self, keys: LinkKeys) -> Self {
95        self.link_security.replica = Some(keys);
96        self
97    }
98
99    /// Encrypt the embed-writer listener: every replica must complete a
100    /// Noise handshake against `keys.local`, and when `keys.peers` is not
101    /// empty, present one of those keys.
102    ///
103    /// ```
104    /// use kevy_embedded::{Config, Keypair, LinkKeys, Store};
105    ///
106    /// let writer = Store::open(
107    ///     Config::default()
108    ///         .with_embed_writer("127.0.0.1:0")
109    ///         .with_writer_security(LinkKeys::new(Keypair::from_secret([1; 32]))),
110    /// )?;
111    /// assert!(writer.writer_addr().is_some());
112    /// # Ok::<(), kevy_embedded::KevyError>(())
113    /// ```
114    #[must_use]
115    pub fn with_writer_security(mut self, keys: LinkKeys) -> Self {
116        self.link_security.writer = Some(keys);
117        self
118    }
119}