From fca86ca59041f4a0d99884f604596cdf7113bb76 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Sat, 27 Jul 2024 23:16:07 +0200 Subject: [PATCH] Add name validation --- Cargo.lock | 2 ++ Cargo.toml | 2 ++ src/definitions/config.rs | 1 + src/definitions/firewall.rs | 5 +++++ src/definitions/network.rs | 8 ++++++++ src/definitions/object.rs | 7 +++++++ src/definitions/service.rs | 5 +++++ src/definitions/system.rs | 5 +++++ src/definitions/vpn.rs | 8 ++++++++ src/main.rs | 1 + src/validation/mod.rs | 16 ++++++++++++++++ 11 files changed, 60 insertions(+) create mode 100644 src/validation/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 95c6898..560f1ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1156,8 +1156,10 @@ dependencies = [ "jsonrpsee", "lazy_static", "macaddr", + "once_cell", "pwhash", "rbtag", + "regex", "serde", "serde_json", "tera", diff --git a/Cargo.toml b/Cargo.toml index e17bb9b..99928fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,6 @@ uuid = { version = "1.5.0", features = ["v4"] } tera = "1" lazy_static = "1.4.0" garde = { version = "0.20.0", features = ["full"] } +once_cell = "1.19.0" +regex = "1.10.5" diff --git a/src/definitions/config.rs b/src/definitions/config.rs index 9b33af3..cc40586 100644 --- a/src/definitions/config.rs +++ b/src/definitions/config.rs @@ -17,6 +17,7 @@ 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, diff --git a/src/definitions/firewall.rs b/src/definitions/firewall.rs index c0f2544..410ad8f 100644 --- a/src/definitions/firewall.rs +++ b/src/definitions/firewall.rs @@ -1,7 +1,9 @@ +use super::config::Config; use garde::Validate; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] pub struct Firewall { #[garde(dive)] pub forward_rules: Vec, @@ -12,6 +14,7 @@ pub struct Firewall { } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct ForwardRule { pub name: String, @@ -24,6 +27,7 @@ pub struct ForwardRule { } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct DestinationNATRule { pub name: String, @@ -37,6 +41,7 @@ pub struct DestinationNATRule { } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct SourceNATRule { pub name: String, diff --git a/src/definitions/network.rs b/src/definitions/network.rs index 64c0de9..902d006 100644 --- a/src/definitions/network.rs +++ b/src/definitions/network.rs @@ -1,8 +1,11 @@ +use super::config::Config; +use crate::validation; use garde::Validate; use ipnet::IpNet; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] pub struct Network { #[garde(dive)] pub interfaces: Vec, @@ -11,8 +14,10 @@ pub struct Network { } #[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, @@ -42,8 +47,10 @@ 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, @@ -53,6 +60,7 @@ pub struct StaticRoute { } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct Link { pub name: String, diff --git a/src/definitions/object.rs b/src/definitions/object.rs index 0deffaf..328158e 100644 --- a/src/definitions/object.rs +++ b/src/definitions/object.rs @@ -1,9 +1,12 @@ +use super::config::Config; +use crate::validation; use garde::Validate; use ipnet::IpNet; use serde::{Deserialize, Serialize}; use std::net::IpAddr; #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] pub struct Object { #[garde(dive)] pub addresses: Vec
, @@ -12,8 +15,10 @@ pub struct Object { } #[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, @@ -29,8 +34,10 @@ 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, diff --git a/src/definitions/service.rs b/src/definitions/service.rs index 9111207..4b9bec6 100644 --- a/src/definitions/service.rs +++ b/src/definitions/service.rs @@ -1,8 +1,10 @@ +use super::config::Config; use garde::Validate; use macaddr::MacAddr8; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] pub struct Service { #[garde(dive)] pub dhcp_servers: Vec, @@ -13,6 +15,7 @@ pub struct Service { } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct DHCPServer { pub name: String, @@ -27,6 +30,7 @@ pub struct DHCPServer { } #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct DNSServer { pub name: String, @@ -35,6 +39,7 @@ pub struct DNSServer { } #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] #[garde(allow_unvalidated)] pub struct NTPServer { pub name: String, diff --git a/src/definitions/system.rs b/src/definitions/system.rs index e53bca0..aad57a5 100644 --- a/src/definitions/system.rs +++ b/src/definitions/system.rs @@ -1,15 +1,20 @@ +use super::config::Config; +use crate::validation; use garde::Validate; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +#[garde(context(Config))] pub struct System { #[garde(dive)] pub users: Vec, } #[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, diff --git a/src/definitions/vpn.rs b/src/definitions/vpn.rs index 0a0fd68..0648674 100644 --- a/src/definitions/vpn.rs +++ b/src/definitions/vpn.rs @@ -1,13 +1,17 @@ +use super::config::Config; +use crate::validation; use garde::Validate; use serde::{Deserialize, Serialize}; #[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, @@ -16,8 +20,10 @@ pub struct Wireguard { } #[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, @@ -27,8 +33,10 @@ 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, diff --git a/src/main.rs b/src/main.rs index b66b9ef..3a4f86d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ mod config_manager; mod definitions; mod state; mod templates; +mod validation; mod web; #[tokio::main] diff --git a/src/validation/mod.rs b/src/validation/mod.rs new file mode 100644 index 0000000..f711c4a --- /dev/null +++ b/src/validation/mod.rs @@ -0,0 +1,16 @@ +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 = 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(()) +}