diff --git a/Application.Deploy.Dockerfile b/Application.Deploy.Dockerfile index db11ed1f..3d8dabe5 100644 --- a/Application.Deploy.Dockerfile +++ b/Application.Deploy.Dockerfile @@ -3,7 +3,8 @@ RUN apk add -U --no-cache wireguard-tools dumb-init FROM alpine_wg AS runtime COPY application/bin/rs-wg /usr/local/cargo/bin/rs-wg -COPY data/wg /etc/wireguard +# COPY data/wireguard /etc/wireguard +CMD [ "mkdir", "/etc/wireguard" ] COPY data/www /etc/www WORKDIR /etc/wireguard EXPOSE 8080 \ No newline at end of file diff --git a/data/wg0.conf b/data/wg0.conf index eacfad92..2d546ed4 100644 --- a/data/wg0.conf +++ b/data/wg0.conf @@ -3,7 +3,7 @@ # Server [Interface] -PrivateKey = aCjYU+CBAkIerzXXFj8hzc4ZmMDLNGrhsxqJjOwtPH0= +PrivateKey = 7djcxyZBiUQ6OrB36p1cKLGHl1zg5MqQShN9Udl41Hw= Address = 10.8.0.1/24 ListenPort = 51820 PreUp = @@ -11,3 +11,9 @@ PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; ip PreDown = PostDown = +# Client: 321 (184a9b70-03b3-4bfb-ae89-ce463634f394) +[Peer] +PublicKey = ej10pb+XPRVuotGrkz+423Lku6Jyf5OHqt0ccjx6KU8= +PresharedKey = Y/5LvXKegqRoeugphZZOLS1/Kl+wN+HdJoCdulxzrEs= +AllowedIPs = 10.8.0.2/32 + diff --git a/data/wg0.json b/data/wg0.json index 1220045d..ca7bbf7f 100644 --- a/data/wg0.json +++ b/data/wg0.json @@ -1,8 +1,20 @@ { "server": { - "privateKey": "aCjYU+CBAkIerzXXFj8hzc4ZmMDLNGrhsxqJjOwtPH0=", - "publicKey": "Gi9QI2VgCJK1ziPaE2gE/jXbiXj+Rx3mUbIq8RcHPEE=", + "privateKey": "7djcxyZBiUQ6OrB36p1cKLGHl1zg5MqQShN9Udl41Hw=", + "publicKey": "kAW7Jefvgqs5H6hyuF05a1vSZJJdAiedg3AnVdgjFVk=", "address": "10.8.0.1" }, - "clients": {} + "clients": { + "184a9b70-03b3-4bfb-ae89-ce463634f394": { + "uuid": "184a9b70-03b3-4bfb-ae89-ce463634f394", + "name": "321", + "address": "10.8.0.2", + "privateKey": "+K2Bi7AYB1pUCWqIPdRIpqnGFOjG0PE7W8pOBLsatXo=", + "publicKey": "ej10pb+XPRVuotGrkz+423Lku6Jyf5OHqt0ccjx6KU8=", + "preSharedKey": "Y/5LvXKegqRoeugphZZOLS1/Kl+wN+HdJoCdulxzrEs=", + "createdAt": "2022-12-18T15:55:49Z", + "updatedAt": "2022-12-18T15:55:49Z", + "enabled": true + } + } } diff --git a/data/www/index.html b/data/www/index.html index a842588e..e69de29b 100644 --- a/data/www/index.html +++ b/data/www/index.html @@ -1,528 +0,0 @@ - - - - - WireGuard - - - - - - - - - - - - -
- -
- -
- - Logout - - - - -

- - WireGuard -

-

- -
-
-
-

There is an update available!

-

{{latestRelease.changelog}}

-
- - - Update → - -
-
- -
-
-
-

Clients

-
-
- -
-
- -
- -
- - -
- -
- - -
- - -
-
-
- -
-
- - - - - -
-
-
-
-
- -
- - -
- - - - {{client.name}} - - - - - - - -
- - -
- - - - - - - {{client.address}} - - - - - - - - - - - - · - - - - {{client.transferTxCurrent | bytes}}/s - - - - - · - - - - {{client.transferRxCurrent | bytes}}/s - - - - - · {{new Date(client.latestHandshakeAt) | timeago}} - -
-
- -
-
- - -
-
-
-
-
-
- - - - - - - - - - - - - -
-
- -
- -
-
-

There are no clients yet.

- -

-
-
- - - - - -
-
-
- - -
-
-
- - -
-
-
- - -
-
- - - - - - - -
-
- - -
-
- - - - - - - -
-
-
- -
-

WireGuard

- -
- -
- - - -
- - - - - - -
-
- -
- - - - - - - -
- -
- -

Made by Emile Nijssen · Donate · GitHub

- - -
- - - - - - - - - \ No newline at end of file diff --git a/data/www/manifest.json b/data/www/manifest.json index 5214f3f3..e69de29b 100644 --- a/data/www/manifest.json +++ b/data/www/manifest.json @@ -1,11 +0,0 @@ -{ - "name": "WireGuard", - "display": "standalone", - "background_color": "#fff", - "icons": [ - { - "src": "img/favicon.png", - "type": "image/png" - } - ] -} \ No newline at end of file diff --git a/docker-compose.deploy.yml b/docker-compose.deploy.yml index 40325a80..5fef99c9 100644 --- a/docker-compose.deploy.yml +++ b/docker-compose.deploy.yml @@ -5,7 +5,7 @@ services: container_name: rs-wg environment: - WIREGUARD_SETTINGS=/etc/wireguard/settings.json - - WIREGUARD_PATH=/etc/wireguard/ + - WIREGUARD_PATH=/etc/wireguard - STATIC_DIR=/etc/www/ - RUST_LOG=actix_web=warn,debug diff --git a/docker-compose.yml b/docker-compose.yml index 3d146da0..9f391bee 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: container_name: rs-wg environment: - WIREGUARD_SETTINGS=/etc/wireguard/settings.json - - WIREGUARD_PATH=/etc/wireguard/ + - WIREGUARD_PATH=/etc/wireguard - STATIC_DIR=/etc/wireguard/www - RUST_LOG=actix_web=warn,debug diff --git a/src/utils/os.rs b/src/utils/os.rs index 7924e8f8..ac119057 100644 --- a/src/utils/os.rs +++ b/src/utils/os.rs @@ -1,8 +1,27 @@ -use std::{ffi::OsStr, string::FromUtf8Error}; +use std::{error::Error, string::FromUtf8Error}; +use futures_util::TryFutureExt; use log::{info, warn}; use serde::Serialize; -use tokio::{fs::File, io::AsyncReadExt, process::Command}; +use tokio::{ + fs::File, + io::{AsyncReadExt, AsyncWriteExt}, + process::Command, +}; + +// pub struct Error { +// error: T, +// } +// impl Error { +// pub fn new(error: T) -> Self { +// Self { error } +// } +// } +// impl ToString for Error { +// fn to_string(&self) -> String { +// self.error.to_string() +// } +// } #[derive(Serialize)] pub struct StdResult { @@ -21,26 +40,38 @@ impl StdResult { } } -pub async fn load_file>(path: S) -> Result { +pub async fn write_file, D: Into>( + path: P, + data: D, +) -> Result<(), std::io::Error> { tokio::fs::OpenOptions::new() - .append(false) - .read(true) - .write(true) .create(true) + .write(true) + .truncate(true) .open(path.into()) + .and_then(|mut file| async move { file.write(data.into().as_bytes()).await.map(|_| file) }) + .and_then(|mut file| async move { file.flush().await }) .await } -pub async fn read_file(mut file: File) -> Result { - let mut dst = String::new(); - file.read_to_string(&mut dst).await.map(|_| dst) +pub async fn read_file>(path: S) -> Result { + tokio::fs::OpenOptions::new() + .create(true) + .write(true) + .read(true) + .open(path.into()) + .and_then(|mut file| async move { + let mut dst = String::new(); + file.read_to_string(&mut dst).await.map(|_| dst) + }) + .await } pub async fn load_file_unhandled(path: &str) -> File { match tokio::fs::OpenOptions::new() - .append(false) .read(true) .write(true) + .truncate(true) .create(true) .open(path) .await @@ -65,27 +96,23 @@ pub async fn load_and_read_file_unhandled(path: &str) -> (File, String) { } } -pub async fn exec_sh>(command: S) -> Result { - let command = command.into(); +pub async fn exec_sh(command: &S) -> Result> { + let command = command.to_string(); info!("$ {}", command.clone()); let res = match Command::new("sh").arg("-c").arg(command).output().await { Ok(val) => val, - Err(err) => return Err(err.to_string()), + Err(err) => return Err(Box::new(err)), }; let stdout_b = &res.stdout.to_vec(); let stderr_b = &res.stderr.to_vec(); - let stdout = match remove_escape(stdout_b) { - Ok(val) => val, - Err(err) => return Err(err.to_string()), - }; - let stderr = match remove_escape(stderr_b) { - Ok(val) => val, - Err(err) => return Err(err.to_string()), - }; - - Ok(StdResult { stdout, stderr }) + match remove_escape(stdout_b) + .and_then(|stdout| remove_escape(stderr_b).map(|stderr| (stdout, stderr))) + { + Ok((stdout, stderr)) => Ok(StdResult { stdout, stderr }), + Err(err) => return Err(Box::new(err)), + } } pub fn remove_escape(bytes: &Vec) -> Result { diff --git a/src/wg_rs/config.rs b/src/wg_rs/config.rs index 5dafb6b4..b57c74a2 100644 --- a/src/wg_rs/config.rs +++ b/src/wg_rs/config.rs @@ -1,11 +1,12 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, error::Error, sync::Arc}; use chrono::{SecondsFormat, SubsecRound, Utc}; use futures_util::TryFutureExt; +use log::error; use serde::{Deserialize, Serialize}; -use tokio::{io::AsyncWriteExt, join}; +use tokio::join; use uuid::Uuid; use crate::utils::{misc, os}; @@ -127,38 +128,45 @@ pub struct Accessor { } impl Accessor { - pub async fn new(memento_path: String, config_path: String, settings: Arc) -> Self { - let memento_str = os::load_file(memento_path.clone()) - .and_then(|file| os::read_file(file)) + pub async fn build( + memento_path: String, + config_path: String, + settings: Arc, + ) -> Result> { + let memento_str = os::read_file(memento_path.clone()) .await .expect("Could not read memento"); - let memento = if memento_str.is_empty() { + if memento_str.is_empty() { log::info!("Creating new WireGuard configuration..."); - let private_key = os::exec_sh("wg genkey").await.expect("error genkey").stdout; - let public_key = os::exec_sh(format!("echo {} | wg pubkey", private_key)) + os::exec_sh(&"wg genkey") + .and_then(|res_public| async move { + os::exec_sh(&format!("echo {} | wg pubkey", &res_public.stdout)) + .await + .map(|res_private| (res_public.stdout, res_private.stdout)) + }) .await - .expect("error pubkey") - .stdout; - - let address = settings.default_address.clone(); - let memento = Memento::new(Server { - private_key, - public_key, - address, - }); - log::info!("WireGuard configuration generated..."); - memento + .and_then(|(public_key, private_key)| { + let address = settings.default_address.clone(); + let memento = Memento::new(Server { + private_key, + public_key, + address, + }); + log::info!("WireGuard configuration generated..."); + Ok(memento) + }) } else { - serde_json::from_str(&memento_str).expect("Could not serialize memento") - }; - - Self { - config_path, - memento_path, - memento, - settings, + Ok(serde_json::from_str(&memento_str).expect("Could not serialize memento")) } + .and_then(|memento| { + Ok(Self { + config_path, + memento_path, + memento, + settings, + }) + }) } pub async fn set(&mut self, memento: Memento) { @@ -169,25 +177,20 @@ impl Accessor { ser_memento.push('\n'); ser_config.push('\n'); - _ = join!( - async { - let mut file = os::load_file(self.memento_path.clone()) - .await - .expect("Could not load memento"); - file.write(ser_memento.as_bytes()) - .await - .expect("Could not write memento"); - }, - async { - let mut file = os::load_file(self.config_path.clone()) - .await - .expect("Could not load config"); - file.write(ser_config.as_bytes()) - .await - .expect("Could not write config"); - } + let (memento_wr, config_wr) = join!( + os::write_file(self.memento_path.clone(), ser_memento), + os::write_file(self.config_path.clone(), ser_config) ); + memento_wr.unwrap_or_else(|err| { + error!("Could not write memento: {}", err); + panic!() + }); + config_wr.unwrap_or_else(|err| { + error!("Could not write config: {}", err); + panic!() + }); + self.memento = memento; } diff --git a/src/wg_rs/wireguard.rs b/src/wg_rs/wireguard.rs index f7770c43..eac22f42 100644 --- a/src/wg_rs/wireguard.rs +++ b/src/wg_rs/wireguard.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use chrono::{SecondsFormat, SubsecRound, Utc}; +use log::error; use uuid::Uuid; use crate::utils::{misc, os}; @@ -17,7 +18,7 @@ pub struct WireGuard { impl WireGuard { pub async fn new(name: &str, wg_path: String, settings: Settings) -> Self { - let path = format!("{}{}", wg_path, name); + let path = format!("{}/{}", wg_path, name); let config_path = format!("{}.conf", path); let memento_path = format!("{}.json", path); let name = format!("{}", name); @@ -27,32 +28,46 @@ impl WireGuard { Self { name, settings: counter.clone(), - memento_accessor: Accessor::new(memento_path, config_path, counter).await, + memento_accessor: Accessor::build(memento_path, config_path, counter) + .await + .unwrap_or_else(|err| { + error!("Error initializing Wireguard: {}", err); + panic!() + }), } } pub async fn quick_up(&self) { - let result = os::exec_sh(format!("wg-quick up {}", &self.name)) + os::exec_sh(&format!("wg-quick up {}", &self.name)) .await - .expect("Error"); - result.log(); + .unwrap_or_else(|err| { + error!("Error quick_up: {}", err); + panic!() + }) + .log(); } pub async fn quick_down(&self) { - let result = os::exec_sh(format!("wg-quick down {}", &self.name)) + os::exec_sh(&format!("wg-quick down {}", &self.name)) .await - .expect("Error"); - result.log(); + .unwrap_or_else(|err| { + error!("Error quick_down: {}", err); + panic!() + }) + .log(); } pub async fn sync_config(&self) { - let result = os::exec_sh(format!( + os::exec_sh(&format!( "wg syncconf {} <(wg-quick strip {})", self.name, self.name )) .await - .expect("Error syncing"); - result.log(); + .unwrap_or_else(|err| { + error!("Error syncing: {}", err); + panic!() + }) + .log(); } pub async fn start(&mut self) { @@ -64,12 +79,18 @@ impl WireGuard { } pub async fn create_client(&mut self, name: String) -> Client { - let private_key = os::exec_sh("wg genkey").await.expect("error genkey").stdout; + let private_key = os::exec_sh(&"wg genkey") + .await + .expect("error genkey") + .stdout; let pub_cmd = format!("echo {} | wg pubkey", private_key); - let public_key = os::exec_sh(pub_cmd).await.expect("error pubkey").stdout; + let public_key = os::exec_sh(&pub_cmd).await.expect("error pubkey").stdout; - let pre_shared_key = os::exec_sh("wg genpsk").await.expect("error genpsk").stdout; + let pre_shared_key = os::exec_sh(&"wg genpsk") + .await + .expect("error genpsk") + .stdout; let mut memento = self.memento_accessor.get(); @@ -122,7 +143,7 @@ impl WireGuard { } pub async fn get_clients(&self) -> Vec { - let res = os::exec_sh("wg show wg0 dump").await.unwrap(); + let res = os::exec_sh(&"wg show wg0 dump").await.unwrap(); let lines: Vec> = res .stdout