aboutsummaryrefslogtreecommitdiff
path: root/src-tauri
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-08-19 18:23:43 +0200
committerHimbeer <himbeer@disroot.org>2024-08-19 18:23:43 +0200
commit4be9a79311189238e2448c820ad3b0cb04bb7ac7 (patch)
tree164fccf680e0128f4d84e9833e8a0927ef21a261 /src-tauri
parentd14e8876bcdabf9022afd72c01594fc68004c43e (diff)
Populate VPN server management page
Diffstat (limited to 'src-tauri')
-rw-r--r--src-tauri/src/main.rs339
1 files changed, 338 insertions, 1 deletions
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index f90cded..da58602 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,6 +1,7 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+use std::io::{BufRead, BufReader};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6};
use std::sync::Mutex;
use std::time::{Duration, SystemTime};
@@ -298,6 +299,20 @@ struct Domain {
status_text: String,
}
+#[derive(Debug, Serialize)]
+struct VpnClient {
+ name: String,
+ pubkey: String,
+ psk: String,
+ allowed_ips: String,
+}
+
+#[derive(Debug, Serialize)]
+struct VpnClients {
+ clients: Vec<VpnClient>,
+ status_text: String,
+}
+
impl FromIterator<Dhcpv4Lease> for Leases {
fn from_iter<T>(iter: T) -> Self
where
@@ -1274,6 +1289,325 @@ async fn handle_log_read_response(response: Response) -> String {
}
}
+#[tauri::command]
+async fn vpnclients(state: State<'_, Mutex<Session>>) -> Result<VpnClients, ()> {
+ let (client, instance) = {
+ let state = state.lock().unwrap();
+ (state.client.clone(), state.instance.clone())
+ };
+ let instance = match instance {
+ Some(instance) => instance,
+ None => {
+ return Ok(VpnClients {
+ clients: Vec::new(),
+ status_text: String::from(
+ "Keine Instanz ausgewählt, bitte melden Sie sich neu an!",
+ ),
+ })
+ }
+ };
+
+ let response = client
+ .get(instance.url.join("/data/read").unwrap())
+ .query(&[("path", "/data/wgd.peers")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .send();
+
+ Ok(match response.await {
+ Ok(response) => handle_vpnclients_response(response).await,
+ Err(e) => VpnClients {
+ clients: Vec::new(),
+ status_text: format!("Abfrage fehlgeschlagen: {}", e),
+ },
+ })
+}
+
+async fn handle_vpnclients_response(response: Response) -> VpnClients {
+ let status = response.status();
+ if status.is_success() {
+ match response.text().await {
+ Ok(peertext) => parse_peertext(peertext),
+ Err(e) => VpnClients {
+ clients: Vec::new(),
+ status_text: format!("Keinen Text vom Server erhalten. Fehler: {}", e),
+ },
+ }
+ } else if status == StatusCode::UNAUTHORIZED {
+ VpnClients {
+ clients: Vec::new(),
+ status_text: String::from(
+ "Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!",
+ ),
+ }
+ } else if status == StatusCode::NOT_FOUND {
+ VpnClients {
+ clients: Vec::new(),
+ status_text: String::new(),
+ }
+ } else if status.is_client_error() {
+ VpnClients {
+ clients: Vec::new(),
+ status_text: format!("Clientseitiger Fehler: {}", status),
+ }
+ } else if status.is_server_error() {
+ VpnClients {
+ clients: Vec::new(),
+ status_text: format!("Serverseitiger Fehler: {}", status),
+ }
+ } else {
+ VpnClients {
+ clients: Vec::new(),
+ status_text: format!("Unerwarteter Statuscode: {}", status),
+ }
+ }
+}
+
+macro_rules! next {
+ ($c:expr, $v:ident) => {
+ match $c.next() {
+ Some(column) => column,
+ None => return VpnClients {
+ clients: $v.clients,
+ status_text: format!("Ungültige Clientdefinition: Fehlende Spalte. Konfigurationsdatei löschen und neu anlegen.")
+ },
+ }
+ };
+
+ ($c:expr, $v:ident, $name:expr) => {
+ match $c.next() {
+ Some(column) => column,
+ None => {
+ $v.clients.push(VpnClient {
+ name: $name,
+ pubkey: String::from("--- FEHLER ---"),
+ psk: String::from("--- FEHLER ---"),
+ allowed_ips: String::from("--- FEHLER ---"),
+ });
+
+ return VpnClients {
+ clients: $v.clients,
+ status_text: format!("Ungültige Clientdefinition: Fehlende Spalte. Fehlerhaften Eintrag (letzte angezeigte Zeile) löschen und nach Korrektur neu anlegen.")
+ };
+ }
+ }
+ }
+}
+
+fn parse_peertext(peertext: String) -> VpnClients {
+ let mut vpnclients = VpnClients {
+ clients: Vec::new(),
+ status_text: String::new(),
+ };
+
+ let br = BufReader::new(peertext.as_bytes());
+ for line in br.lines() {
+ let line = line.expect("read line from peertext string");
+
+ let mut columns = line.split_whitespace();
+
+ let name = next!(columns, vpnclients);
+ let pubkey = next!(columns, vpnclients, name.to_string());
+ let psk = next!(columns, vpnclients, name.to_string());
+
+ let mut allowed_ips = String::new();
+ let mut delim = "";
+ for column in columns {
+ allowed_ips += delim;
+ allowed_ips += column;
+ delim = " ";
+ }
+
+ vpnclients.clients.push(VpnClient {
+ name: name.to_string(),
+ pubkey: pubkey.to_string(),
+ psk: psk.to_string(),
+ allowed_ips,
+ });
+ }
+
+ vpnclients
+}
+
+#[tauri::command]
+async fn vpndel(name: String, state: State<'_, Mutex<Session>>) -> Result<String, ()> {
+ let (client, instance) = {
+ let state = state.lock().unwrap();
+ (state.client.clone(), state.instance.clone())
+ };
+ let instance = match instance {
+ Some(instance) => instance,
+ None => {
+ return Ok(String::from(
+ "Keine Instanz ausgewählt, bitte melden Sie sich neu an!",
+ ))
+ }
+ };
+
+ let response = client
+ .get(instance.url.join("/data/read").unwrap())
+ .query(&[("path", "/data/wgd.peers")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .send();
+
+ let peertext = match response.await {
+ Ok(response) => match handle_vpndel_response(response).await {
+ Ok(peertext) => peertext,
+ Err(status_text) => return Ok(status_text),
+ },
+ Err(e) => format!("Abfrage fehlgeschlagen: {}", e),
+ };
+
+ let mut new_peertext = String::new();
+
+ let br = BufReader::new(peertext.as_bytes());
+ for line in br.lines() {
+ let line = line.expect("read line from peertext string");
+
+ if !line.starts_with(&name) {
+ new_peertext += &line;
+ new_peertext += "\n";
+ }
+ }
+
+ let response = client
+ .post(instance.url.join("/data/write").unwrap())
+ .query(&[("path", "/data/wgd.peers")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .body(new_peertext)
+ .send();
+
+ Ok(match response.await {
+ Ok(response) => handle_vpndel_response2(response),
+ Err(e) => format!("Löschung fehlgeschlagen: {}", e),
+ })
+}
+
+async fn handle_vpndel_response(response: Response) -> Result<String, String> {
+ let status = response.status();
+ if status.is_success() {
+ match response.text().await {
+ Ok(peertext) => Ok(peertext),
+ Err(e) => Err(format!("Keinen Text vom Server erhalten. Fehler: {}", e)),
+ }
+ } else if status == StatusCode::NOT_FOUND {
+ Err(String::from(
+ "Konfigurationsdatei existiert nicht, Löschung nicht nötig",
+ ))
+ } else if status == StatusCode::UNAUTHORIZED {
+ Err(String::from(
+ "Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!",
+ ))
+ } else if status.is_client_error() {
+ Err(format!("Clientseitiger Fehler: {}", status))
+ } else if status.is_server_error() {
+ Err(format!("Serverseitiger Fehler: {}", status))
+ } else {
+ Err(format!("Unerwarteter Statuscode: {}", status))
+ }
+}
+
+fn handle_vpndel_response2(response: Response) -> String {
+ let status = response.status();
+ if status.is_success() {
+ String::from("Löschung erfolgreich")
+ } else if status == StatusCode::UNAUTHORIZED {
+ String::from("Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!")
+ } else if status.is_client_error() {
+ format!("Clientseitiger Fehler: {}", status)
+ } else if status.is_server_error() {
+ format!("Serverseitiger Fehler: {}", status)
+ } else {
+ format!("Unerwarteter Statuscode: {}", status)
+ }
+}
+
+#[tauri::command]
+async fn vpnadd(
+ name: String,
+ pubkey: String,
+ psk: String,
+ allowed_ips: String,
+ state: State<'_, Mutex<Session>>,
+) -> Result<String, ()> {
+ let (client, instance) = {
+ let state = state.lock().unwrap();
+ (state.client.clone(), state.instance.clone())
+ };
+ let instance = match instance {
+ Some(instance) => instance,
+ None => {
+ return Ok(String::from(
+ "Keine Instanz ausgewählt, bitte melden Sie sich neu an!",
+ ))
+ }
+ };
+
+ let response = client
+ .get(instance.url.join("/data/read").unwrap())
+ .query(&[("path", "/data/wgd.peers")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .send();
+
+ let mut peertext = match response.await {
+ Ok(response) => match handle_vpnadd_response(response).await {
+ Ok(peertext) => peertext,
+ Err(status_text) => return Ok(status_text),
+ },
+ Err(e) => format!("Abfrage fehlgeschlagen: {}", e),
+ };
+
+ peertext += &format!("{} {} {} {}\n", name, pubkey, psk, allowed_ips);
+
+ let response = client
+ .post(instance.url.join("/data/write").unwrap())
+ .query(&[("path", "/data/wgd.peers")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .body(peertext)
+ .send();
+
+ Ok(match response.await {
+ Ok(response) => handle_vpnadd_response2(response),
+ Err(e) => format!("Hinzufügen fehlgeschlagen: {}", e),
+ })
+}
+
+async fn handle_vpnadd_response(response: Response) -> Result<String, String> {
+ let status = response.status();
+ if status.is_success() {
+ match response.text().await {
+ Ok(peertext) => Ok(peertext),
+ Err(e) => Err(format!("Keinen Text vom Server erhalten. Fehler: {}", e)),
+ }
+ } else if status == StatusCode::NOT_FOUND {
+ Ok(String::new())
+ } else if status == StatusCode::UNAUTHORIZED {
+ Err(String::from(
+ "Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!",
+ ))
+ } else if status.is_client_error() {
+ Err(format!("Clientseitiger Fehler: {}", status))
+ } else if status.is_server_error() {
+ Err(format!("Serverseitiger Fehler: {}", status))
+ } else {
+ Err(format!("Unerwarteter Statuscode: {}", status))
+ }
+}
+
+fn handle_vpnadd_response2(response: Response) -> String {
+ let status = response.status();
+ if status.is_success() {
+ String::from("Hinzufügen erfolgreich")
+ } else if status == StatusCode::UNAUTHORIZED {
+ String::from("Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!")
+ } else if status.is_client_error() {
+ format!("Clientseitiger Fehler: {}", status)
+ } else if status.is_server_error() {
+ format!("Serverseitiger Fehler: {}", status)
+ } else {
+ format!("Unerwarteter Statuscode: {}", status)
+ }
+}
+
fn main() {
tauri::Builder::default()
.manage(Mutex::new(Session {
@@ -1304,7 +1638,10 @@ fn main() {
change_sys_password,
reboot,
shutdown,
- log_read
+ log_read,
+ vpnclients,
+ vpndel,
+ vpnadd
])
.run(tauri::generate_context!())
.expect("error while running tauri application");