use std::path::Path;
use crate::vortix_core::ports::tunnel::{
ParseError, ParsedProfile, Tunnel, TunnelCapabilities, TunnelError, TunnelHandle,
TunnelKindTag, TunnelStatus,
};
use crate::vortix_core::profile::{Profile, ProfileId, ProtocolKind};
use crate::vortix_protocol_openvpn::OvpnTunnel;
use crate::vortix_protocol_wireguard::WgTunnel;
use crate::state::{Protocol, VpnProfile};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TunnelKind {
WireGuard(WgTunnel),
OpenVpn(OvpnTunnel),
Mock(crate::vortix_core::ports::tunnel::mock::MockTunnel),
}
impl TunnelKind {
pub fn up(&mut self, profile: &Profile) -> Result<TunnelHandle, TunnelError> {
match self {
Self::WireGuard(t) => t.up(profile),
Self::OpenVpn(t) => t.up(profile),
Self::Mock(t) => t.up(profile),
}
}
pub fn down(&mut self, handle: TunnelHandle) -> Result<(), TunnelError> {
match self {
Self::WireGuard(t) => t.down(handle),
Self::OpenVpn(t) => t.down(handle),
Self::Mock(t) => t.down(handle),
}
}
pub fn status(&self, handle: &TunnelHandle) -> Result<TunnelStatus, TunnelError> {
match self {
Self::WireGuard(t) => t.status(handle),
Self::OpenVpn(t) => t.status(handle),
Self::Mock(t) => t.status(handle),
}
}
pub fn parse_profile(&self, raw: &[u8]) -> Result<Box<dyn ParsedProfile>, ParseError> {
match self {
Self::WireGuard(t) => t.parse_profile(raw),
Self::OpenVpn(t) => t.parse_profile(raw),
Self::Mock(t) => t.parse_profile(raw),
}
}
#[must_use]
pub fn capabilities(&self) -> TunnelCapabilities {
match self {
Self::WireGuard(t) => t.capabilities(),
Self::OpenVpn(t) => t.capabilities(),
Self::Mock(t) => t.capabilities(),
}
}
#[must_use]
pub fn kind_tag(&self) -> TunnelKindTag {
match self {
Self::WireGuard(t) => t.kind_tag(),
Self::OpenVpn(t) => t.kind_tag(),
Self::Mock(t) => t.kind_tag(),
}
}
}
impl crate::vortix_core::ports::tunnel::Tunnel for TunnelKind {
fn up(&mut self, profile: &Profile) -> Result<TunnelHandle, TunnelError> {
TunnelKind::up(self, profile)
}
fn down(&mut self, handle: TunnelHandle) -> Result<(), TunnelError> {
TunnelKind::down(self, handle)
}
fn status(&self, handle: &TunnelHandle) -> Result<TunnelStatus, TunnelError> {
TunnelKind::status(self, handle)
}
fn parse_profile(&self, raw: &[u8]) -> Result<Box<dyn ParsedProfile>, ParseError> {
TunnelKind::parse_profile(self, raw)
}
fn capabilities(&self) -> TunnelCapabilities {
TunnelKind::capabilities(self)
}
fn kind_tag(&self) -> TunnelKindTag {
TunnelKind::kind_tag(self)
}
}
#[must_use]
pub fn tunnel_for_with_secrets(
protocol: Protocol,
config_dir: &Path,
ovpn_verbosity: &str,
connect_timeout_secs: u64,
) -> TunnelKind {
let mut kind = tunnel_for(protocol, config_dir, ovpn_verbosity, connect_timeout_secs);
if let TunnelKind::OpenVpn(ref mut ovpn) = kind {
let store_dir = config_dir.to_path_buf();
let provider: crate::vortix_protocol_openvpn::SecretProvider =
std::sync::Arc::new(move |profile_id: &str| {
use crate::vortix_config::secret_store::{
LayeredSecretStore, SecretBackendTag, SecretRef, SecretStore, SecretStoreConfig,
};
let store = LayeredSecretStore::new(SecretStoreConfig {
fallback_path: store_dir.join("secrets.enc"),
passphrase: None,
force_fallback: false,
})
.ok()?;
let id = format!("creds/{profile_id}");
for backend in [SecretBackendTag::Keyring, SecretBackendTag::EncryptedFile] {
let r = SecretRef::new(backend, &id);
if let Ok(s) = store.get(&r) {
return Some(s.as_bytes().to_vec());
}
}
None
});
let updated = ovpn.clone().with_secret_provider(provider);
*ovpn = updated;
}
kind
}
#[must_use]
pub fn tunnel_for(
protocol: Protocol,
config_dir: &Path,
ovpn_verbosity: &str,
connect_timeout_secs: u64,
) -> TunnelKind {
match protocol {
Protocol::WireGuard => TunnelKind::WireGuard(WgTunnel::new()),
Protocol::OpenVPN => TunnelKind::OpenVpn(
OvpnTunnel::new(config_dir.join(crate::constants::OPENVPN_RUN_DIR))
.with_auth_dir(config_dir.join(crate::constants::OPENVPN_AUTH_DIR))
.with_verbosity(ovpn_verbosity)
.with_connect_timeout(connect_timeout_secs),
),
}
}
#[must_use]
pub fn profile_view(p: &VpnProfile) -> Profile {
Profile::new(
ProfileId::new(&p.name),
&p.name,
match p.protocol {
Protocol::WireGuard => ProtocolKind::WireGuard,
Protocol::OpenVPN => ProtocolKind::OpenVpn,
},
p.config_path.clone(),
)
}