117 lines
3.3 KiB
Rust
117 lines
3.3 KiB
Rust
use std::error::Error;
|
|
|
|
use base64::{Engine, prelude::BASE64_STANDARD};
|
|
use sqlx::{PgPool, query, query_as, types::ipnetwork::IpNetwork};
|
|
use x25519_dalek::StaticSecret;
|
|
|
|
use crate::config::WireguardConfig;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Interface {
|
|
pub name: String,
|
|
pub address: IpNetwork,
|
|
pub port: u16,
|
|
pub private_key: StaticSecret,
|
|
pub default_network_netmask: u8,
|
|
}
|
|
|
|
struct InterfacePostgres {
|
|
name: String,
|
|
address: IpNetwork,
|
|
port: i32,
|
|
private_key: Vec<u8>,
|
|
default_network_netmask: i16,
|
|
}
|
|
|
|
impl TryFrom<WireguardConfig> for Interface {
|
|
type Error = Box<dyn Error + Send + Sync>;
|
|
|
|
fn try_from(config: WireguardConfig) -> Result<Self, Self::Error> {
|
|
Ok(Self {
|
|
name: config.interface,
|
|
address: config.address,
|
|
port: config.port,
|
|
private_key: {
|
|
let decoded_key = BASE64_STANDARD.decode(config.private_key)?;
|
|
let key_array: [u8; 32] =
|
|
decoded_key.try_into().map_err(|_| "Invalid key length")?;
|
|
StaticSecret::from(key_array)
|
|
},
|
|
default_network_netmask: config.default_network_netmask,
|
|
})
|
|
}
|
|
}
|
|
|
|
// We allow .unwrap() here because we set the lengths of the variables ourselves
|
|
#[allow(clippy::fallible_impl_from)]
|
|
impl From<InterfacePostgres> for Interface {
|
|
fn from(row: InterfacePostgres) -> Self {
|
|
Self {
|
|
name: row.name,
|
|
address: row.address,
|
|
port: row.port.try_into().unwrap(),
|
|
private_key: {
|
|
let key_array: [u8; 32] = row.private_key.try_into().unwrap();
|
|
StaticSecret::from(key_array)
|
|
},
|
|
default_network_netmask: row.default_network_netmask.try_into().unwrap(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Interface> for InterfacePostgres {
|
|
fn from(interface: Interface) -> Self {
|
|
Self {
|
|
name: interface.name,
|
|
address: interface.address,
|
|
port: i32::from(interface.port),
|
|
private_key: interface.private_key.to_bytes().to_vec(),
|
|
default_network_netmask: i16::from(interface.default_network_netmask),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Interface {
|
|
pub async fn insert(
|
|
pool: &PgPool,
|
|
interface: Self,
|
|
) -> Result<(), Box<dyn Error + Send + Sync>> {
|
|
let interface = InterfacePostgres::from(interface);
|
|
|
|
query!(
|
|
r#"
|
|
INSERT INTO interfaces (name, address, port, private_key, default_network_netmask)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
"#,
|
|
interface.name,
|
|
interface.address,
|
|
interface.port,
|
|
interface.private_key,
|
|
interface.default_network_netmask,
|
|
)
|
|
.execute(pool)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn select_by_name(
|
|
pool: &PgPool,
|
|
name: &str,
|
|
) -> Result<Option<Self>, Box<dyn Error + Send + Sync>> {
|
|
let row = query_as!(
|
|
InterfacePostgres,
|
|
r#"
|
|
SELECT name, address, port, private_key, default_network_netmask
|
|
FROM interfaces
|
|
WHERE name = $1
|
|
"#,
|
|
name
|
|
)
|
|
.fetch_optional(pool)
|
|
.await?;
|
|
|
|
row.map_or_else(|| Ok(None), |row| Ok(Some(Self::from(row))))
|
|
}
|
|
}
|