1use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair};
8use std::fs;
9use std::path::Path;
10
11pub fn generate_certificate(
16 common_name: &str,
17) -> Result<(String, String, String), String> {
18 let mut params = CertificateParams::new(vec![common_name.to_string()])
19 .map_err(|e| format!("cert params: {}", e))?;
20
21 let mut dn = DistinguishedName::new();
23 dn.push(DnType::CommonName, common_name);
24 params.distinguished_name = dn;
25
26 let key_pair = KeyPair::generate()
28 .map_err(|e| format!("key gen: {}", e))?;
29
30 let cert = params
31 .self_signed(&key_pair)
32 .map_err(|e| format!("self-sign: {}", e))?;
33
34 let cert_pem = cert.pem();
35 let key_pem = key_pair.serialize_pem();
36
37 let fingerprint = pwr_core::crypto::sha256_hex(cert_pem.as_bytes());
39
40 Ok((cert_pem, key_pem, fingerprint))
41}
42
43pub fn save_certificate(
45 cert_path: &Path,
46 key_path: &Path,
47 cert_pem: &str,
48 key_pem: &str,
49) -> Result<(), String> {
50 if let Some(parent) = cert_path.parent() {
52 fs::create_dir_all(parent)
53 .map_err(|e| format!("mkdir {}: {}", parent.display(), e))?;
54 }
55 if let Some(parent) = key_path.parent() {
56 fs::create_dir_all(parent)
57 .map_err(|e| format!("mkdir {}: {}", parent.display(), e))?;
58 }
59
60 fs::write(cert_path, cert_pem)
62 .map_err(|e| format!("write cert: {}", e))?;
63
64 fs::write(key_path, key_pem)
66 .map_err(|e| format!("write key: {}", e))?;
67
68 #[cfg(unix)]
69 {
70 use std::os::unix::fs::PermissionsExt;
71 let mut perms = fs::metadata(key_path)
72 .map_err(|e| format!("stat key: {}", e))?
73 .permissions();
74 perms.set_mode(0o600);
75 fs::set_permissions(key_path, perms)
76 .map_err(|e| format!("chmod key: {}", e))?;
77 }
78
79 Ok(())
80}
81
82pub fn init_server(
92 config_dir: &Path,
93 storage_dir: &Path,
94 hostname: &str,
95) -> Result<(), String> {
96 use crate::config::{save_config, ServerConfig};
97
98 let (cert_pem, key_pem, fingerprint) = generate_certificate(hostname)?;
99
100 let cert_path = config_dir.join("server.crt");
101 let key_path = config_dir.join("server.key");
102 let config_path = config_dir.join("server.toml");
103
104 save_certificate(&cert_path, &key_path, &cert_pem, &key_pem)?;
105
106 let psk = pwr_core::crypto::generate_psk();
108 let psk_hex = pwr_core::crypto::psk_to_hex(&psk);
109
110 let mut config = ServerConfig::default();
111 config.auth_token = psk_hex.clone();
112 config.tls_cert_path = cert_path.clone();
113 config.tls_key_path = key_path.clone();
114 config.storage_base_path = storage_dir.to_path_buf();
115
116 save_config(&config, &config_path)?;
117
118 println!("Server initialized successfully.");
119 println!(" Config: {}", config_path.display());
120 println!(" Certificate: {}", cert_path.display());
121 println!(" Private key: {}", key_path.display());
122 println!(" Storage: {}", storage_dir.display());
123 println!(" PSK: {}", psk_hex);
124 println!(" Fingerprint: {}", fingerprint);
125 println!();
126 println!("Copy the PSK to your client config:");
127 println!(" pwr init --server-host {} --psk {}", hostname, psk_hex);
128 println!();
129 println!("To start the server:");
130 println!(" pwr-server --config {} start", config_path.display());
131
132 Ok(())
133}