Compare commits

..

No commits in common. "cfb3d0a3b0d029a0ac16ac6395221bf91645230a" and "2c050ae61d9ff31280cc094318514c01c89f3c2c" have entirely different histories.

13 changed files with 520 additions and 952 deletions

1247
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -22,9 +22,7 @@ tower-http = "0.4.4"
tracing = "0.1.40"
tracing-subscriber = "0.3.17"
uuid = { version = "1.5.0", features = ["v4"] }
validator = { version = "0.15", features = ["derive"] }
tera = "1"
lazy_static = "1.4.0"
garde = { version = "0.20.0", features = ["full"] }
once_cell = "1.19.0"
regex = "1.10.5"

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { apiCall } from "../../api";
import getPlugins from "../../plugins";
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
const p = getPlugins();
let peers = $ref({});
@ -8,81 +8,65 @@ let loading = $ref(false);
let selection = $ref([] as number[]);
const columns = [
{ heading: "Name", path: "name" },
{ heading: "Allowed IPs", path: "allowed_ips" },
{ heading: "Endpoint", path: "endpoint" },
{ heading: "Persistent Keepalive", path: "persistent_keepalive" },
{ heading: "Comment", path: "comment" },
{heading: 'Name', path: 'name'},
{heading: 'Allowed IPs', path: 'allowed_ips'},
{heading: 'Endpoint', path: 'endpoint'},
{heading: 'Persistent Keepalive', path: 'persistent_keepalive'},
{heading: 'Comment', path: 'comment'},
];
const displayData = $computed(() => {
let data: any;
data = [];
for (const index in peers) {
data.push({
name: peers[index].name,
allowed_ips: peers[index].allowed_ips,
endpoint: peers[index].endpoint,
persistent_keepalive: peers[index].persistent_keepalive,
comment: peers[index].comment,
});
}
return data;
let data: any;
data = [];
for (const name in peers) {
data.push({
name,
allowed_ips: peers[name].allowed_ips,
endpoint: peers[name].endpoint,
persistent_keepalive: peers[name].persistent_keepalive,
comment: peers[name].comment,
});
}
return data;
});
async function load() {
loading = true;
let res = await apiCall("vpn.wireguard.peers.list", {});
if (res.Error === null) {
console.debug("peers", res.Data);
peers = res.Data;
} else {
console.debug("error", res);
}
loading = false;
async function load(){
loading = true;
let res = await apiCall('vpn.wireguard.peers.list', {});
if (res.Error === null) {
console.debug('peers', res.Data);
peers = res.Data;
} else {
console.debug('error', res);
}
loading = false;
}
async function deletePeer() {
let res = await apiCall("vpn.wireguard.peers.delete", {
name: displayData[selection[0]].name,
});
if (res.Error === null) {
console.debug("deleted peer");
} else {
console.debug("error", res);
}
load();
async function deletePeer(){
let res = await apiCall('vpn.wireguard.peers.delete', {name: displayData[selection[0]].name});
if (res.Error === null) {
console.debug('deleted peer');
} else {
console.debug('error', res);
}
load();
}
async function editPeer() {
p.router.push(
`/vpn/wireguard.peers/edit/${displayData[selection[0]].name}`,
);
p.router.push(`/vpn/wireguard.peers/edit/${ displayData[selection[0]].name}`);
}
onMounted(async () => {
load();
onMounted(async() => {
load();
});
</script>
<template>
<TableView
v-model:selection="selection"
v-model:data="displayData"
title="Peers"
:columns="columns"
:loading="loading"
:table-props="{ sort: true, sortSelf: true }"
>
<button @click="load">Refresh</button>
<router-link class="button" to="/vpn/wireguard.peers/edit"
>Create</router-link
>
<button :disabled="selection.length != 1" @click="editPeer">
Edit
</button>
<button :disabled="selection.length != 1" @click="deletePeer">
Delete
</button>
</TableView>
</template>
<TableView v-model:selection="selection" v-model:data="displayData" title="Peers" :columns="columns" :loading="loading" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button>
<router-link class="button" to="/vpn/wireguard.peers/edit">Create</router-link>
<button :disabled="selection.length != 1" @click="editPeer">Edit</button>
<button :disabled="selection.length != 1" @click="deletePeer">Delete</button>
</TableView>
</template>

View file

@ -1,11 +1,11 @@
use super::definitions::config::Config;
use garde::Validate;
use pwhash::sha512_crypt;
use serde::Serialize;
use std::fs;
use std::sync::{Arc, Mutex, MutexGuard};
use thiserror::Error;
use tracing::{error, info};
use validator::Validate;
#[derive(Error, Debug)]
pub enum ConfigError {
@ -13,7 +13,7 @@ pub enum ConfigError {
SerdeError(#[from] serde_json::Error),
#[error("Validation Error")]
ValidatonError(#[from] garde::Report),
ValidatonError(#[from] validator::ValidationErrors),
#[error("Hash Error")]
HashError(#[from] pwhash::error::Error),

View file

@ -1,5 +1,5 @@
use garde::Validate;
use serde::{Deserialize, Serialize};
use validator::Validate;
use super::firewall;
use super::firewall::SNATType;
@ -17,21 +17,13 @@ use super::vpn;
use crate::macro_db;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Config {
#[garde(skip)]
pub config_version: u64,
#[garde(dive)]
pub network: network::Network,
#[garde(dive)]
pub object: object::Object,
#[garde(dive)]
pub system: system::System,
#[garde(dive)]
pub service: service::Service,
#[garde(dive)]
pub vpn: vpn::VPN,
#[garde(dive)]
pub firewall: firewall::Firewall,
}

View file

@ -1,21 +1,14 @@
use super::config::Config;
use garde::Validate;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Firewall {
#[garde(dive)]
pub forward_rules: Vec<ForwardRule>,
#[garde(dive)]
pub destination_nat_rules: Vec<DestinationNATRule>,
#[garde(dive)]
pub source_nat_rules: Vec<SourceNATRule>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct ForwardRule {
pub name: String,
pub services: Vec<String>,
@ -27,8 +20,6 @@ pub struct ForwardRule {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct DestinationNATRule {
pub name: String,
pub services: Vec<String>,
@ -41,8 +32,6 @@ pub struct DestinationNATRule {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct SourceNATRule {
pub name: String,
pub services: Vec<String>,

View file

@ -1,23 +1,15 @@
use super::config::Config;
use crate::validation;
use garde::Validate;
use ipnet::IpNet;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Network {
#[garde(dive)]
pub interfaces: Vec<NetworkInterface>,
#[garde(dive)]
pub static_routes: Vec<StaticRoute>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct NetworkInterface {
#[garde(custom(validation::validate_name))]
pub name: String,
pub alias: String,
pub comment: String,
@ -47,10 +39,7 @@ pub enum AddressingMode {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct StaticRoute {
#[garde(custom(validation::validate_name))]
pub name: String,
pub interface: String,
pub gateway: String,
@ -60,8 +49,6 @@ pub struct StaticRoute {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct Link {
pub name: String,
}

View file

@ -1,24 +1,16 @@
use super::config::Config;
use crate::validation;
use garde::Validate;
use ipnet::IpNet;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Object {
#[garde(dive)]
pub addresses: Vec<Address>,
#[garde(dive)]
pub services: Vec<Service>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct Address {
#[garde(custom(validation::validate_name))]
pub name: String,
pub address_type: AddressType,
pub comment: String,
@ -34,10 +26,7 @@ pub enum AddressType {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct Service {
#[garde(custom(validation::validate_name))]
pub name: String,
pub service_type: ServiceType,
pub comment: String,

View file

@ -1,22 +1,15 @@
use super::config::Config;
use garde::Validate;
use macaddr::MacAddr8;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Service {
#[garde(dive)]
pub dhcp_servers: Vec<DHCPServer>,
#[garde(dive)]
pub dns_servers: Vec<DNSServer>,
#[garde(dive)]
pub ntp_servers: Vec<NTPServer>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct DHCPServer {
pub name: String,
pub interface: String,
@ -30,8 +23,6 @@ pub struct DHCPServer {
}
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct DNSServer {
pub name: String,
pub interface: String,
@ -39,8 +30,6 @@ pub struct DNSServer {
}
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct NTPServer {
pub name: String,
pub interface: String,

View file

@ -1,20 +1,13 @@
use super::config::Config;
use crate::validation;
use garde::Validate;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct System {
#[garde(dive)]
pub users: Vec<User>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct User {
#[garde(custom(validation::validate_name))]
pub name: String,
pub comment: String,
pub hash: String,

View file

@ -1,29 +1,19 @@
use super::config::Config;
use crate::validation;
use garde::Validate;
use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct VPN {
#[garde(dive)]
pub wireguard: Wireguard,
}
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
#[garde(context(Config))]
pub struct Wireguard {
#[garde(dive)]
pub interfaces: Vec<WireguardInterface>,
#[garde(dive)]
pub peers: Vec<WireguardPeer>,
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct WireguardInterface {
#[garde(custom(validation::validate_name))]
pub name: String,
pub public_key: String,
pub private_key: String,
@ -33,10 +23,7 @@ pub struct WireguardInterface {
}
#[derive(Serialize, Deserialize, Clone, Validate, Debug)]
#[garde(context(Config))]
#[garde(allow_unvalidated)]
pub struct WireguardPeer {
#[garde(custom(validation::validate_name))]
pub name: String,
pub public_key: String,
pub preshared_key: Option<String>,

View file

@ -25,7 +25,6 @@ mod config_manager;
mod definitions;
mod state;
mod templates;
mod validation;
mod web;
#[tokio::main]

View file

@ -1,16 +0,0 @@
use {
crate::definitions::config::Config, garde::rules::pattern::Matcher, once_cell::sync::Lazy,
regex::Regex,
};
pub fn validate_name(value: &str, _: &Config) -> garde::Result {
if value.len() > 32 {
return Err(garde::Error::new("name is longer than 32"));
}
static RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"/^[0-9A-Za-z_-]*$/g").unwrap());
if !RE.is_match(value) {
return Err(garde::Error::new("name must only contain 0-9A-Za-z_-"));
}
Ok(())
}