use std::{num::NonZeroU16, path::PathBuf};
use sequoia_openpgp::crypto::Password;
use serde::{Deserialize, Serialize};
use crate::config::Credentials;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
#[serde(default = "default_state_directory")]
pub state_directory: PathBuf,
#[serde(default = "default_socket_path")]
pub signer_socket_path: PathBuf,
pub bridge_hostname: String,
pub bridge_port: u16,
pub connection_pool_size: usize,
pub user_password_length: NonZeroU16,
pub credentials: Credentials,
pub certificate_subject: X509SubjectName,
pub openpgp_user_id: String,
#[serde(default)]
pub pkcs11_bindings: Vec<Pkcs11Binding>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct X509SubjectName {
pub country: String,
pub state_or_province: String,
pub locality: String,
pub organization: String,
pub organizational_unit: String,
}
impl Default for X509SubjectName {
fn default() -> Self {
Self {
country: "US".to_string(),
state_or_province: "Massachusetts".to_string(),
locality: "Cambridge".to_string(),
organization: "An Example Organization".to_string(),
organizational_unit: "Example Department of the Organization".to_string(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Pkcs11Binding {
pub certificate: PathBuf,
pub private_key: Option<String>,
#[doc(hidden)]
#[serde(skip)]
pub pin: Option<Password>,
}
impl Pkcs11Binding {
pub(crate) fn can_unbind(&self) -> bool {
self.private_key.is_some() && self.pin.is_some()
}
}
impl Config {
pub fn database(&self) -> PathBuf {
self.state_directory.join("siguldry.sqlite")
}
}
impl Default for Config {
fn default() -> Self {
Self {
state_directory: default_state_directory(),
signer_socket_path: default_socket_path(),
bridge_hostname: "bridge.example.com".to_string(),
bridge_port: 44333,
connection_pool_size: 32,
user_password_length: NonZeroU16::new(32).unwrap(),
credentials: Credentials {
private_key: PathBuf::from("siguldry.server.private_key.pem"),
certificate: PathBuf::from("siguldry.server.certificate.pem"),
ca_certificate: PathBuf::from("siguldry.ca_certificate.pem"),
},
pkcs11_bindings: vec![],
certificate_subject: Default::default(),
openpgp_user_id: "Test Signing <sign@example.com>".to_string(),
}
}
}
impl std::fmt::Display for Config {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
toml::ser::to_string_pretty(&self).unwrap_or_default()
)
}
}
fn default_socket_path() -> PathBuf {
PathBuf::from("/run/siguldry-signer/signer.socket")
}
fn default_state_directory() -> PathBuf {
PathBuf::from("/var/lib/siguldry/")
}
#[cfg(test)]
mod tests {
#[test]
fn load_example_config() -> anyhow::Result<()> {
let example_conf_path =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("server.toml.example");
let example_conf = std::fs::read_to_string(&example_conf_path)?;
toml::de::from_str::<super::Config>(&example_conf)?;
Ok(())
}
}