use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair};
use std::fs;
use std::path::Path;
pub fn generate_certificate(
common_name: &str,
) -> Result<(String, String, String), String> {
let mut params = CertificateParams::new(vec![common_name.to_string()])
.map_err(|e| format!("cert params: {}", e))?;
let mut dn = DistinguishedName::new();
dn.push(DnType::CommonName, common_name);
params.distinguished_name = dn;
let key_pair = KeyPair::generate()
.map_err(|e| format!("key gen: {}", e))?;
let cert = params
.self_signed(&key_pair)
.map_err(|e| format!("self-sign: {}", e))?;
let cert_pem = cert.pem();
let key_pem = key_pair.serialize_pem();
let fingerprint = pwr_core::crypto::sha256_hex(cert_pem.as_bytes());
Ok((cert_pem, key_pem, fingerprint))
}
pub fn save_certificate(
cert_path: &Path,
key_path: &Path,
cert_pem: &str,
key_pem: &str,
) -> Result<(), String> {
if let Some(parent) = cert_path.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("mkdir {}: {}", parent.display(), e))?;
}
if let Some(parent) = key_path.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("mkdir {}: {}", parent.display(), e))?;
}
fs::write(cert_path, cert_pem)
.map_err(|e| format!("write cert: {}", e))?;
fs::write(key_path, key_pem)
.map_err(|e| format!("write key: {}", e))?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(key_path)
.map_err(|e| format!("stat key: {}", e))?
.permissions();
perms.set_mode(0o600);
fs::set_permissions(key_path, perms)
.map_err(|e| format!("chmod key: {}", e))?;
}
Ok(())
}
pub fn init_server(
config_dir: &Path,
storage_dir: &Path,
hostname: &str,
) -> Result<(), String> {
use crate::config::{save_config, ServerConfig};
let (cert_pem, key_pem, fingerprint) = generate_certificate(hostname)?;
let cert_path = config_dir.join("server.crt");
let key_path = config_dir.join("server.key");
let config_path = config_dir.join("server.toml");
save_certificate(&cert_path, &key_path, &cert_pem, &key_pem)?;
let psk = pwr_core::crypto::generate_psk();
let psk_hex = pwr_core::crypto::psk_to_hex(&psk);
let mut config = ServerConfig::default();
config.auth_token = psk_hex.clone();
config.tls_cert_path = cert_path.clone();
config.tls_key_path = key_path.clone();
config.storage_base_path = storage_dir.to_path_buf();
save_config(&config, &config_path)?;
println!("Server initialized successfully.");
println!(" Config: {}", config_path.display());
println!(" Certificate: {}", cert_path.display());
println!(" Private key: {}", key_path.display());
println!(" Storage: {}", storage_dir.display());
println!(" PSK: {}", psk_hex);
println!(" Fingerprint: {}", fingerprint);
println!();
println!("Copy the PSK to your client config:");
println!(" pwr init --server-host {} --psk {}", hostname, psk_hex);
println!();
println!("To start the server:");
println!(" pwr-server --config {} start", config_path.display());
println!();
println!("To install as a systemd user service (no root needed):");
println!(" mkdir -p ~/.config/systemd/user");
println!(" cp pwr-server.user.service ~/.config/systemd/user/pwr-server.service");
println!(" systemctl --user daemon-reload");
println!(" systemctl --user enable --now pwr-server");
println!();
println!("To have the service survive logout:");
println!(" sudo loginctl enable-linger $USER");
Ok(())
}