porta-rs 0.1.1

Zero-trust CGNAT bypass via WireGuard tunnel
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

use super::schema::Role;

/// Allowed client entry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AllowedClient {
    /// Client identifier
    pub id: String,

    /// Client's WireGuard public key
    pub pubkey: String,

    /// Client's HMAC secret (for authentication)
    pub hmac_secret: String,
}

/// Server configuration (machine with public IP)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    /// Role of this instance
    pub role: Role,

    /// Port to listen for WireGuard connections
    pub listen_port: u16,

    /// WireGuard interface name
    pub interface: String,

    /// Server VPN IP with CIDR (e.g., "10.0.0.1/24")
    pub ip: String,

    /// Data directory for storing state
    #[serde(default = "default_data_dir")]
    pub data_dir: String,

    /// WireGuard public key
    pub public_key: String,

    /// List of allowed clients
    #[serde(default)]
    pub allowed_clients: Vec<AllowedClient>,
}

fn default_data_dir() -> String {
    "/var/lib/porta".to_string()
}

impl ServerConfig {
    pub fn save(&self) -> Result<()> {
        let config_dir = PathBuf::from("/etc/porta");
        fs::create_dir_all(&config_dir)?;

        let config_path = config_dir.join("server.toml");
        let content = toml::to_string_pretty(self)?;
        fs::write(&config_path, content)?;

        Ok(())
    }

    pub fn data_path(&self) -> PathBuf {
        PathBuf::from(&self.data_dir)
    }
}