flmodules/
nodeconfig.rs

1//! Configuration structures that define a node, including old versions for migrations.
2//! Also configuration for starting a new node.
3//!
4//! All node-configurations can be serialized with serde and offer nice hex
5//! based serializations when using text-based serializations like `yaml` or `json`.
6
7use bitflags::bitflags;
8use ed25519_compact::{KeyPair, Noise, PublicKey, Seed, Signature};
9use flarch::nodeids::{NodeID, U256};
10use flmacro::VersionedSerde;
11use serde_derive::{Deserialize, Serialize};
12use serde_with::{base64::Base64, hex::Hex, serde_as};
13use std::fmt::{Debug, Formatter};
14use thiserror::Error;
15
16use crate::Modules;
17
18/// Errors to be returned when setting up a new config
19#[derive(Error, Debug)]
20pub enum ConfigError {
21    /// If the public key cannot be found in the toml string
22    #[error("Didn't find public key")]
23    PublicKeyMissing,
24    /// Error while decoding the toml string
25    #[error("Couldn't decode")]
26    NoInfo,
27    /// Serde error
28    #[error(transparent)]
29    DecodeYaml(#[from] serde_yaml::Error),
30}
31
32/// NodeInfo is the public information of the node.
33#[serde_as]
34#[derive(VersionedSerde, Clone, Hash)]
35#[versions = "[NodeInfoV1,NodeInfoV2]"]
36pub struct NodeInfo {
37    /// Name of the node, up to 256 bytes
38    pub name: String,
39    /// What client this node runs on - "Node" or the navigator id
40    pub client: String,
41    /// the public key of the node
42    #[serde_as(as = "Hex")]
43    pub pubkey: Vec<u8>,
44    // capabilities of this node
45    pub modules: Modules,
46    #[serde(skip)]
47    id: Option<NodeID>,
48}
49
50impl NodeInfo {
51    /// Creates a new NodeInfo with a random name.
52    pub fn new(pubkey: PublicKey) -> NodeInfo {
53        NodeInfo {
54            name: names::Generator::default().next().unwrap(),
55            client: "libc".to_string(),
56            pubkey: pubkey.as_ref().to_vec(),
57            modules: Modules::stable(),
58            id: None,
59        }
60    }
61
62    pub fn new_from_id(id: NodeID) -> NodeInfo {
63        let keypair = KeyPair::from_seed(Seed::default());
64        Self::new_from_id_kp(id, keypair.pk)
65    }
66
67    pub fn new_from_id_kp(id: NodeID, pubkey: PublicKey) -> NodeInfo {
68        NodeInfo {
69            name: names::Generator::default().next().unwrap(),
70            client: "libc".to_string(),
71            pubkey: pubkey.as_ref().to_vec(),
72            modules: Modules::stable(),
73            id: Some(id),
74        }
75    }
76
77    /// Returns the unique id, based on the public key.
78    pub fn get_id(&self) -> U256 {
79        if let Some(id) = self.id {
80            return id;
81        }
82        let a: [u8; PublicKey::BYTES] = self.pubkey.clone().try_into().unwrap();
83        U256::from(a)
84    }
85
86    /// Verifies a signature with the public key of this `NodeInfo`
87    pub fn verify(&self, msg: &[u8], sig_bytes: &[u8]) -> bool {
88        let pubkey = PublicKey::from_slice(&self.pubkey).unwrap();
89        let sig = match Signature::from_slice(sig_bytes) {
90            Ok(sig) => sig,
91            Err(_) => return false,
92        };
93        pubkey.verify(msg, &sig).is_ok()
94    }
95
96    /// Decodes a given string as yaml and returns the corresponding `NodeInfo`.
97    pub fn decode(data: &str) -> Result<Self, ConfigError> {
98        Ok(serde_yaml::from_str(data)?)
99    }
100
101    /// Encodes this NodeInfo as yaml string.
102    pub fn encode(&self) -> String {
103        serde_yaml::to_string(&self).unwrap()
104    }
105}
106
107impl Debug for NodeInfo {
108    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
109        let pubkey: String = self.pubkey.iter().map(|b| format!("{:02x}", b)).collect();
110
111        write!(
112            f,
113            "NodeInfo: {{ info: '{}', client: '{}', pubkey: {} }}",
114            self.name, self.client, pubkey
115        )
116    }
117}
118
119impl PartialEq for NodeInfo {
120    fn eq(&self, other: &Self) -> bool {
121        self.get_id() == other.get_id()
122    }
123}
124
125impl Eq for NodeInfo {}
126
127impl From<NodeInfoV2> for NodeInfo {
128    fn from(old: NodeInfoV2) -> Self {
129        Self {
130            name: old.name,
131            client: old.client,
132            pubkey: old.pubkey,
133            modules: old.modules.into(),
134            id: None,
135        }
136    }
137}
138
139#[serde_as]
140#[derive(Serialize, Deserialize, Clone)]
141struct NodeInfoV2 {
142    /// Name of the node, up to 256 bytes
143    pub name: String,
144    /// What client this node runs on - "Node" or the navigator id
145    pub client: String,
146    /// the public key of the node
147    #[serde_as(as = "Base64")]
148    pub pubkey: Vec<u8>,
149    // capabilities of this node
150    #[serde(default = "ModulesV2::all")]
151    pub modules: ModulesV2,
152    #[serde(skip)]
153    _id: Option<NodeID>,
154}
155
156impl Into<Modules> for ModulesV2 {
157    fn into(self) -> Modules {
158        Modules::from_bits(self.bits()).unwrap_or(Modules::stable())
159    }
160}
161
162bitflags! {
163    #[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Hash)]
164    pub struct ModulesV2: u32 {
165        const ENABLE_STAT = 0x1;
166        const ENABLE_RAND = 0x2;
167        const ENABLE_GOSSIP = 0x4;
168        const ENABLE_PING = 0x8;
169        const ENABLE_WEBPROXY = 0x10;
170        const ENABLE_WEBPROXY_REQUESTS = 0x20;
171    }
172}
173
174impl From<NodeInfoV1> for NodeInfoV2 {
175    fn from(_: NodeInfoV1) -> Self {
176        panic!("Old configuration not supported anymore")
177    }
178}
179
180// This is not used anymore, so it's empty.
181#[derive(Serialize, Deserialize, Clone)]
182struct NodeInfoV1 {}
183
184/// NodeConfig is stored on the node itself and contains the private key.
185#[serde_as]
186#[derive(VersionedSerde, Debug, PartialEq)]
187#[versions = "[NodeConfigV1]"]
188pub struct NodeConfig {
189    /// info about this node
190    pub info: NodeInfo,
191    /// the cryptographic keypair as a vector of bytes
192    #[serde_as(as = "Hex")]
193    pub keypair: Vec<u8>,
194}
195
196impl Default for NodeConfig {
197    fn default() -> Self {
198        Self::new()
199    }
200}
201
202impl NodeConfig {
203    /// Returns a new NodeConfig
204    pub fn new() -> Self {
205        let keypair = KeyPair::from_seed(Seed::default());
206        NodeConfig {
207            info: NodeInfo::new(keypair.pk),
208            keypair: keypair.as_ref().to_vec(),
209        }
210    }
211
212    /// Returns a new NodeConfig with an overwriting id
213    pub fn new_id(id: NodeID) -> Self {
214        let keypair = KeyPair::from_seed(Seed::default());
215        NodeConfig {
216            info: NodeInfo::new_from_id_kp(id, keypair.pk),
217            keypair: keypair.as_ref().to_vec(),
218        }
219    }
220
221    /// Returns a yaml representation of the config.
222    pub fn encode(&self) -> String {
223        serde_yaml::to_string(&self).unwrap()
224    }
225
226    /// Returns the configuration or an error. Correctly handles
227    /// old toml-configurations.
228    pub fn decode(data: &str) -> Self {
229        serde_yaml::from_str(data)
230            .ok()
231            .unwrap_or_else(|| Self::new())
232    }
233
234    /// Returns the signature on the given hash with the private
235    /// key stored in the config. The hash must be of length 32
236    /// bytes.
237    pub fn sign(&self, hash: [u8; 32]) -> Vec<u8> {
238        let keypair = KeyPair::from_slice(&self.keypair).unwrap();
239        keypair.sk.sign(&hash, Some(Noise::default())).to_vec()
240    }
241}
242
243impl Clone for NodeConfig {
244    fn clone(&self) -> Self {
245        NodeConfig {
246            info: self.info.clone(),
247            keypair: self.keypair.clone(),
248        }
249    }
250}
251
252#[serde_as]
253#[derive(Serialize, Deserialize, Clone)]
254struct NodeConfigV1 {
255    /// info about this node
256    info: NodeInfoV2,
257    /// the cryptographic keypair as a vector of bytes
258    #[serde_as(as = "Base64")]
259    keypair: Vec<u8>,
260}
261
262impl From<NodeConfigV1> for NodeConfig {
263    fn from(old: NodeConfigV1) -> Self {
264        Self {
265            info: old.info.into(),
266            keypair: old.keypair,
267        }
268    }
269}
270
271#[cfg(test)]
272mod tests {
273    use flarch::start_logging_filter_level;
274
275    use super::*;
276
277    #[test]
278    fn save_load() -> Result<(), ConfigError> {
279        start_logging_filter_level(vec![], log::LevelFilter::Debug);
280
281        let nc = NodeConfig::new();
282        let nc_str = nc.encode();
283        log::debug!("NodeConfig is: {nc_str}");
284        let nc_clone = NodeConfig::decode(&nc_str);
285        assert_eq!(nc.keypair, nc_clone.keypair);
286        assert_eq!(nc.info.pubkey, nc_clone.info.pubkey);
287
288        let i = nc.info.clone();
289        let ncv1 = NodeConfigVersion::NodeConfigV1(NodeConfigV1 {
290            info: NodeInfoV2 {
291                name: i.name,
292                client: i.client,
293                pubkey: i.pubkey,
294                modules: ModulesV2::all(),
295                _id: i.id,
296            },
297            keypair: nc.keypair.clone(),
298        });
299        let ncv1_str = serde_yaml::to_string(&ncv1)?;
300        let ncv2 = NodeConfig::decode(&ncv1_str);
301        println!("{ncv1_str}");
302        assert_eq!(ncv2, nc);
303        Ok(())
304    }
305
306    #[test]
307    fn node_info_serde() -> anyhow::Result<()>{
308        let nc = NodeConfig::new();
309        let ni = nc.info;
310        let ni_str = ni.encode();
311        let ni_clone = NodeInfo::decode(&ni_str)?;
312        assert_eq!(ni, ni_clone);
313        
314        Ok(())
315    }
316}