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