porta-rs 0.1.1

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

use super::schema::{PortMapping, Role};

/// Client configuration (machine behind CGNAT)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientConfig {
    /// Role of this instance
    pub role: Role,

    /// Public IP address of the server
    pub server_address: String,

    /// WireGuard port on the server
    pub server_port: u16,

    /// Local WireGuard interface name
    pub local_interface: String,

    /// Local VPN IP with CIDR (e.g., "10.0.0.2/32")
    pub local_ip: String,

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

    /// Unique identifier for this client
    pub client_id: String,

    /// HMAC secret for authentication
    pub hmac_secret: String,

    /// WireGuard public key
    pub public_key: String,

    /// Port forwarding mappings
    #[serde(default)]
    pub ports: Vec<PortMapping>,
}

impl ClientConfig {
    pub fn save(&self) -> Result<()> {
        let config_dir = dirs::config_dir()
            .context("Failed to determine config directory")?
            .join("porta");

        fs::create_dir_all(&config_dir)?;

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

        Ok(())
    }
}