1use std::fs;
8use std::path::{Path, PathBuf};
9
10use anyhow::{anyhow, Result};
11use rustls::pki_types::{CertificateDer, PrivateKeyDer};
12
13pub fn default_cert_dir() -> PathBuf {
15 let home = std::env::var("HOME")
16 .or_else(|_| std::env::var("USERPROFILE"))
17 .unwrap_or_else(|_| ".".to_string());
18 PathBuf::from(home).join(".trustee").join("certs")
19}
20
21pub fn ensure_certs(cert_dir: &Path) -> Result<(PathBuf, PathBuf)> {
26 let cert_path = cert_dir.join("cert.pem");
27 let key_path = cert_dir.join("key.pem");
28
29 if cert_path.exists() && key_path.exists() {
30 tracing::debug!("Using existing certificates at {}", cert_dir.display());
31 return Ok((cert_path, key_path));
32 }
33
34 fs::create_dir_all(cert_dir)?;
35
36 let cert = rcgen::generate_simple_self_signed(vec![
38 "localhost".into(),
39 "127.0.0.1".into(),
40 "::1".into(),
41 ])?;
42
43 let cert_pem = cert.cert.pem();
44 let key_pem = cert.signing_key.serialize_pem();
45
46 fs::write(&cert_path, cert_pem)?;
47 fs::write(&key_path, &key_pem)?;
48 #[cfg(unix)]
50 {
51 use std::os::unix::fs::PermissionsExt;
52 fs::set_permissions(&key_path, fs::Permissions::from_mode(0o600))?;
53 }
54
55 tracing::info!(
56 "Generated self-signed certificate at {}",
57 cert_dir.display()
58 );
59
60 Ok((cert_path, key_path))
61}
62
63pub fn load_tls_config(cert_path: &Path, key_path: &Path) -> Result<rustls::ServerConfig> {
65 let cert_bytes = fs::read(cert_path)?;
66 let key_bytes = fs::read(key_path)?;
67
68 let certs: Vec<CertificateDer<'static>> = rustls_pemfile::certs(&mut cert_bytes.as_slice())
70 .collect::<Result<Vec<_>, _>>()
71 .map_err(|e| anyhow!("Failed to parse certificate PEM: {}", e))?;
72
73 if certs.is_empty() {
74 return Err(anyhow!("No certificates found in {}", cert_path.display()));
75 }
76
77 let key: PrivateKeyDer<'static> = rustls_pemfile::private_key(&mut key_bytes.as_slice())?
79 .ok_or_else(|| anyhow!("No private key found in {}", key_path.display()))?;
80
81 let config = rustls::ServerConfig::builder()
83 .with_no_client_auth()
84 .with_single_cert(certs, key)
85 .map_err(|e| anyhow!("Failed to build TLS config: {}", e))?;
86
87 Ok(config)
88}