use std::path::PathBuf;
use crate::apply::{schema_err, value_as_list, value_as_string};
use crate::error::ValueError;
use crate::parse::Item;
use crate::schema::{Config, ConfigError};
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
#[non_exhaustive]
pub struct SecureSection {
pub private_key_file: Option<PathBuf>,
pub listen_port: u16,
pub client_keys: Vec<[u8; 32]>,
pub cluster_port_base: u16,
pub announce_cluster_port_base: u16,
}
pub fn key_from_hex(s: &str) -> Result<[u8; 32], ValueError> {
let s = s.trim();
if s.len() != 64 || !s.bytes().all(|b| b.is_ascii_hexdigit()) {
return Err(ValueError::new(format!("a key is 64 hex characters, got {s:?}")));
}
let mut k = [0u8; 32];
for (i, b) in k.iter_mut().enumerate() {
*b = u8::from_str_radix(&s[2 * i..2 * i + 2], 16).expect("two hex digits");
}
Ok(k)
}
pub fn key_to_hex(k: &[u8; 32]) -> String {
k.iter().map(|b| format!("{b:02x}")).collect()
}
pub(crate) fn key_item(item: &Item) -> Result<[u8; 32], ConfigError> {
key_from_hex(&value_as_string(item)?).map_err(|e| schema_err(item, e.to_string()))
}
pub(crate) fn peer_keys_item(item: &Item) -> Result<Vec<(String, [u8; 32])>, ConfigError> {
value_as_list(item)?
.iter()
.map(|t| {
let (id, key) = t
.split_once('=')
.ok_or_else(|| schema_err(item, format!("{t:?} is not id=key")))?;
let key = key_from_hex(key).map_err(|e| schema_err(item, e.to_string()))?;
Ok((id.trim().to_string(), key))
})
.collect()
}
pub(crate) fn keys_item(item: &Item) -> Result<Vec<[u8; 32]>, ConfigError> {
value_as_list(item)?
.iter()
.map(|k| key_from_hex(k).map_err(|e| schema_err(item, e.to_string())))
.collect()
}
impl Config {
pub(crate) fn apply_secure(&mut self, item: &Item) -> Result<(), ConfigError> {
match item.key.as_str() {
"private_key_file" => {
self.secure.private_key_file = Some(PathBuf::from(value_as_string(item)?))
}
"listen_port" => self.secure.listen_port = crate::apply::value_as_u16(item)?,
"client_keys" => self.secure.client_keys = keys_item(item)?,
"cluster_port_base" => {
self.secure.cluster_port_base = crate::apply::value_as_u16(item)?
}
"announce_cluster_port_base" => {
self.secure.announce_cluster_port_base = crate::apply::value_as_u16(item)?
}
k => return Err(schema_err(item, format!("unknown [secure] key: {k}"))),
}
Ok(())
}
}