From 568d8cac5c923848707bb9c82281cf9c9271b2c8 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Mon, 6 Nov 2023 02:34:34 +0100 Subject: [PATCH] Convert maps to vecs with name field --- .../pages/[subsystem]/[entity]/edit/index.vue | 9 +- src/api/firewall.rs | 30 +-- src/api/mod.rs | 247 ++++++++---------- src/api/network.rs | 29 +- src/api/object.rs | 30 ++- src/api/service.rs | 30 +-- src/api/system.rs | 137 ++++------ src/api/vpn.rs | 26 +- src/config_manager.rs | 12 +- src/definitions/mod.rs | 14 + src/definitions/network.rs | 9 +- src/definitions/object.rs | 14 +- src/definitions/system.rs | 8 +- src/definitions/vpn.rs | 13 +- src/web/auth.rs | 13 +- 15 files changed, 305 insertions(+), 316 deletions(-) diff --git a/client/src/pages/[subsystem]/[entity]/edit/index.vue b/client/src/pages/[subsystem]/[entity]/edit/index.vue index e7b097d..d5e30b2 100644 --- a/client/src/pages/[subsystem]/[entity]/edit/index.vue +++ b/client/src/pages/[subsystem]/[entity]/edit/index.vue @@ -12,14 +12,7 @@ let vm: any = $ref({}); async function create() { console.debug('value', vm); let res: any; - if (editTypes[subsystem][entity].idType == 'Number') { - res = await apiCall(`${subsystem }.${entity}.create`, vm); - } else { - // TODO find way to only have a name/id field in the form on create and not put it into the value - let id = vm.name; - delete vm.name; - res = await apiCall(`${subsystem }.${entity}.create`, {id: id, thing: vm}); - } + res = await apiCall(`${subsystem }.${entity}.create`, vm); if (res.Error === null) { p.toast.success(`Created ${ editTypes[subsystem][entity].name}`); diff --git a/src/api/firewall.rs b/src/api/firewall.rs index 76d1fb5..768f6e1 100644 --- a/src/api/firewall.rs +++ b/src/api/firewall.rs @@ -1,10 +1,10 @@ use super::ApiError; use crate::{ - create_vec_thing, + create_thing, definitions::firewall::{DestinationNATRule, ForwardRule, SourceNATRule}, - delete_vec_thing, get_vec_thing, list_things, + delete_thing_by_index, get_thing_by_index, list_things, state::RpcState, - update_vec_thing, + update_thing_by_index, }; use jsonrpsee::RpcModule; @@ -12,7 +12,7 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "firewall.forward_rules.get", - get_vec_thing!(firewall.forward_rules), + get_thing_by_index!(firewall.forward_rules), ) .unwrap(); @@ -26,28 +26,28 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "firewall.forward_rules.create", - create_vec_thing!(firewall.forward_rules, ForwardRule), + create_thing!(firewall.forward_rules, ForwardRule), ) .unwrap(); module .register_method( "firewall.forward_rules.update", - update_vec_thing!(firewall.forward_rules, ForwardRule), + update_thing_by_index!(firewall.forward_rules, ForwardRule), ) .unwrap(); module .register_method( "firewall.forward_rules.delete", - delete_vec_thing!(firewall.forward_rules), + delete_thing_by_index!(firewall.forward_rules), ) .unwrap(); module .register_method( "firewall.destination_nat_rules.get", - get_vec_thing!(firewall.destination_nat_rules), + get_thing_by_index!(firewall.destination_nat_rules), ) .unwrap(); @@ -61,28 +61,28 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "firewall.destination_nat_rules.create", - create_vec_thing!(firewall.destination_nat_rules, DestinationNATRule), + create_thing!(firewall.destination_nat_rules, DestinationNATRule), ) .unwrap(); module .register_method( "firewall.destination_nat_rules.update", - update_vec_thing!(firewall.destination_nat_rules, DestinationNATRule), + update_thing_by_index!(firewall.destination_nat_rules, DestinationNATRule), ) .unwrap(); module .register_method( "firewall.destination_nat_rules.delete", - delete_vec_thing!(firewall.destination_nat_rules), + delete_thing_by_index!(firewall.destination_nat_rules), ) .unwrap(); module .register_method( "firewall.source_nat_rules.get", - get_vec_thing!(firewall.source_nat_rules), + get_thing_by_index!(firewall.source_nat_rules), ) .unwrap(); @@ -96,21 +96,21 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "firewall.source_nat_rules.create", - create_vec_thing!(firewall.source_nat_rules, SourceNATRule), + create_thing!(firewall.source_nat_rules, SourceNATRule), ) .unwrap(); module .register_method( "firewall.source_nat_rules.update", - update_vec_thing!(firewall.source_nat_rules, SourceNATRule), + update_thing_by_index!(firewall.source_nat_rules, SourceNATRule), ) .unwrap(); module .register_method( "firewall.source_nat_rules.delete", - delete_vec_thing!(firewall.source_nat_rules), + delete_thing_by_index!(firewall.source_nat_rules), ) .unwrap(); } diff --git a/src/api/mod.rs b/src/api/mod.rs index 33c356d..b737670 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -19,9 +19,8 @@ pub enum ApiError { #[error("Not Found")] NotFound, - #[error("Already Exists")] - AlreadyExists, - + //#[error("Already Exists")] + //AlreadyExists, #[error("Hash Error")] HashError(#[from] pwhash::error::Error), @@ -44,50 +43,53 @@ impl Into> for ApiError { } #[macro_export] -macro_rules! get_map_thing { +macro_rules! get_thing_by_name { ($( $sub_system:ident ).+) => { |params, state| { use serde::Deserialize; #[derive(Deserialize)] - struct GetStringID { - id: String, + struct GetByName { + name: String, } - let t: GetStringID = params.parse().map_err(ApiError::ParameterDeserialize)?; + let t: GetByName = params.parse().map_err(ApiError::ParameterDeserialize)?; - match state - .config_manager - .get_pending_config() - .$($sub_system).+ - .get(&t.id) - { - Some(thing) => Ok(thing.clone()), - None => Err(ApiError::NotFound), + let index = state + .config_manager + .get_pending_config() + .$($sub_system).+.iter().position(|e| *e.name == t.name); + + match index { + Some(i) => Ok(state + .config_manager + .get_pending_config() + .$($sub_system).+[i].clone()), + None => Err(ApiError::NotFound) } } }; } #[macro_export] -macro_rules! get_vec_thing { +macro_rules! get_thing_by_index { ($( $sub_system:ident ).+) => { |params, state| { use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] - struct GetIntID { - id: i64, + struct GetByIndex { + index: i64, } - let t: GetIntID = params.parse().map_err(ApiError::ParameterDeserialize)?; + let t: GetByIndex = params.parse().map_err(ApiError::ParameterDeserialize)?; let things = state .config_manager .get_pending_config() .$($sub_system).+; - if things.len() > t.id as usize { - Ok(things[t.id as usize].clone()) + if things.len() > t.index as usize { + Ok(things[t.index as usize].clone()) } else { Err(ApiError::NotFound) } @@ -108,38 +110,7 @@ macro_rules! list_things { } #[macro_export] -macro_rules! create_map_thing { - ($( $sub_system:ident ).+, $typ:ty) => { - |params, state| { - use serde::{Deserialize, Serialize}; - - #[derive(Deserialize, Serialize)] - struct CreateThing { - id: String, - thing: $typ - } - - let t: CreateThing = params.parse().map_err(ApiError::ParameterDeserialize)?; - let mut cm = state.config_manager.clone(); - let mut tx = cm.start_transaction(); - - if tx.config.$($sub_system).+.insert(t.id.clone(), t.thing).is_none() { - tx.commit(crate::config_manager::Change { - action: crate::config_manager::ChangeAction::Create, - path: stringify!($($sub_system).+), - id: t.id, - }) - .map_err(ApiError::ConfigError) - } else { - tx.revert(); - Err(ApiError::AlreadyExists) - } - } - }; -} - -#[macro_export] -macro_rules! create_vec_thing { +macro_rules! create_thing { ($( $sub_system:ident ).+, $typ:ty) => { |params, state| { let t: $typ = params.parse().map_err(ApiError::ParameterDeserialize)?; @@ -160,93 +131,34 @@ macro_rules! create_vec_thing { } #[macro_export] -macro_rules! update_map_thing { +macro_rules! update_thing_by_name { ($( $sub_system:ident ).+, $typ:ty) => { |params, state| { use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] - struct CreateThing { - id: String, + struct UpdateByName { + name: String, thing: $typ } - let t: CreateThing = params.parse().map_err(ApiError::ParameterDeserialize)?; + let t: UpdateByName = params.parse().map_err(ApiError::ParameterDeserialize)?; let mut cm = state.config_manager.clone(); let mut tx = cm.start_transaction(); - if tx.config.$($sub_system).+.insert(t.id.clone(), t.thing).is_none() { - tx.revert(); - Err(ApiError::NotFound) - } else { - tx.commit(crate::config_manager::Change { - action: crate::config_manager::ChangeAction::Update, - path: stringify!($($sub_system).+), - id: t.id, - }) - .map_err(ApiError::ConfigError) - } - } - }; -} + let index = tx.config.$($sub_system).+.iter().position(|e| *e.name == t.name); -#[macro_export] -macro_rules! update_vec_thing { - ($( $sub_system:ident ).+, $typ:ty) => { - |params, state| { - use serde::{Deserialize, Serialize}; + match index { + Some(i) => { + tx.config.$($sub_system).+[i] = t.thing; - #[derive(Deserialize, Serialize)] - struct CreateThing { - id: i64, - thing: $typ - } - - let t: CreateThing = params.parse().map_err(ApiError::ParameterDeserialize)?; - let mut cm = state.config_manager.clone(); - let mut tx = cm.start_transaction(); - - if tx.config.$($sub_system).+.len() > t.id as usize { - tx.config.$($sub_system).+[t.id as usize] = t.thing; - - tx.commit(crate::config_manager::Change { - action: crate::config_manager::ChangeAction::Update, - path: stringify!($($sub_system).+), - id: t.id.to_string(), - }) - .map_err(ApiError::ConfigError) - } else { - tx.revert(); - Err(ApiError::NotFound) - } - } - }; -} - -#[macro_export] -macro_rules! delete_map_thing { - ($( $sub_system:ident ).+) => { - |params, state| { - use serde::{Deserialize, Serialize}; - - #[derive(Deserialize, Serialize)] - struct GetStringID { - id: String, - } - - let t: GetStringID = params.parse().map_err(ApiError::ParameterDeserialize)?; - - let mut cm = state.config_manager.clone(); - let mut tx = cm.start_transaction(); - - match tx.config.$($sub_system).+.remove(&t.id) { - Some(_) => tx - .commit(crate::config_manager::Change { - action: crate::config_manager::ChangeAction::Delete, + tx.commit(crate::config_manager::Change { + action: crate::config_manager::ChangeAction::Update, path: stringify!($($sub_system).+), - id: t.id, + id: t.name, }) - .map_err(ApiError::ConfigError), + .map_err(ApiError::ConfigError) + } None => { tx.revert(); Err(ApiError::NotFound) @@ -257,27 +169,98 @@ macro_rules! delete_map_thing { } #[macro_export] -macro_rules! delete_vec_thing { +macro_rules! update_thing_by_index { + ($( $sub_system:ident ).+, $typ:ty) => { + |params, state| { + use serde::{Deserialize, Serialize}; + + #[derive(Deserialize, Serialize)] + struct UpdateByIndex { + index: i64, + thing: $typ + } + + let t: UpdateByIndex = params.parse().map_err(ApiError::ParameterDeserialize)?; + let mut cm = state.config_manager.clone(); + let mut tx = cm.start_transaction(); + + if tx.config.$($sub_system).+.len() > t.index as usize { + tx.config.$($sub_system).+[t.index as usize] = t.thing; + + tx.commit(crate::config_manager::Change { + action: crate::config_manager::ChangeAction::Update, + path: stringify!($($sub_system).+), + id: t.index.to_string(), + }) + .map_err(ApiError::ConfigError) + } else { + tx.revert(); + Err(ApiError::NotFound) + } + } + }; +} + +#[macro_export] +macro_rules! delete_thing_by_name { ($( $sub_system:ident ).+) => { |params, state| { use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] - struct GetIntID { - id: i64, + struct DeleteByName { + name: String, } - let t: GetIntID = params.parse().map_err(ApiError::ParameterDeserialize)?; + let t: DeleteByName = params.parse().map_err(ApiError::ParameterDeserialize)?; let mut cm = state.config_manager.clone(); let mut tx = cm.start_transaction(); - if tx.config.$($sub_system).+.len() > t.id as usize { - tx.config.$($sub_system).+.remove(t.id as usize); + let index = tx.config.$($sub_system).+.iter().position(|e| *e.name == t.name); + + match index { + Some(i) => { + tx.config.$($sub_system).+.remove(i); + + tx.commit(crate::config_manager::Change { + action: crate::config_manager::ChangeAction::Delete, + path: stringify!($($sub_system).+), + id: t.name, + }) + .map_err(ApiError::ConfigError) + } + None => { + tx.revert(); + Err(ApiError::NotFound) + } + } + } + }; +} + +#[macro_export] +macro_rules! delete_thing_by_index { + ($( $sub_system:ident ).+) => { + |params, state| { + use serde::{Deserialize, Serialize}; + + #[derive(Deserialize, Serialize)] + struct DeleteByIndex { + index: i64, + } + + let t: DeleteByIndex = params.parse().map_err(ApiError::ParameterDeserialize)?; + + let mut cm = state.config_manager.clone(); + let mut tx = cm.start_transaction(); + + if tx.config.$($sub_system).+.len() > t.index as usize { + tx.config.$($sub_system).+.remove(t.index as usize); tx.commit(crate::config_manager::Change { action: crate::config_manager::ChangeAction::Delete, path: stringify!($($sub_system).+), - id: t.id.to_string(), + id: t.index.to_string(), }) .map_err(ApiError::ConfigError) } else { diff --git a/src/api/network.rs b/src/api/network.rs index b998db7..4cd8932 100644 --- a/src/api/network.rs +++ b/src/api/network.rs @@ -1,19 +1,19 @@ use super::ApiError; use crate::{ - create_map_thing, create_vec_thing, + create_thing, definitions::network::{NetworkInterface, StaticRoute}, - delete_map_thing, delete_vec_thing, get_map_thing, get_vec_thing, list_things, + delete_thing_by_index, delete_thing_by_name, get_thing_by_index, get_thing_by_name, + list_things, state::RpcState, - update_map_thing, update_vec_thing, + update_thing_by_index, update_thing_by_name, }; use jsonrpsee::RpcModule; -use std::collections::HashMap; pub fn register_methods(module: &mut RpcModule) { module .register_method( "network.static_routes.get", - get_vec_thing!(network.static_routes), + get_thing_by_index!(network.static_routes), ) .unwrap(); @@ -27,30 +27,33 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "network.static_routes.create", - create_vec_thing!(network.static_routes, StaticRoute), + create_thing!(network.static_routes, StaticRoute), ) .unwrap(); module .register_method( "network.static_routes.update", - update_vec_thing!(network.static_routes, StaticRoute), + update_thing_by_index!(network.static_routes, StaticRoute), ) .unwrap(); module .register_method( "network.static_routes.delete", - delete_vec_thing!(network.static_routes), + delete_thing_by_index!(network.static_routes), ) .unwrap(); module - .register_method("network.interfaces.get", get_map_thing!(network.interfaces)) + .register_method( + "network.interfaces.get", + get_thing_by_name!(network.interfaces), + ) .unwrap(); module - .register_method::, ApiError>, _>( + .register_method::, ApiError>, _>( "network.interfaces.list", list_things!(network.interfaces), ) @@ -59,21 +62,21 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "network.interfaces.create", - create_map_thing!(network.interfaces, NetworkInterface), + create_thing!(network.interfaces, NetworkInterface), ) .unwrap(); module .register_method( "network.interfaces.update", - update_map_thing!(network.interfaces, NetworkInterface), + update_thing_by_name!(network.interfaces, NetworkInterface), ) .unwrap(); module .register_method( "network.interfaces.delete", - delete_map_thing!(network.interfaces), + delete_thing_by_name!(network.interfaces), ) .unwrap(); } diff --git a/src/api/object.rs b/src/api/object.rs index 7baab32..6a7169a 100644 --- a/src/api/object.rs +++ b/src/api/object.rs @@ -1,21 +1,20 @@ use super::ApiError; use crate::{ - create_map_thing, + create_thing, definitions::object::{Address, Service}, - delete_map_thing, get_map_thing, list_things, + delete_thing_by_name, get_thing_by_name, list_things, state::RpcState, - update_map_thing, + update_thing_by_name, }; use jsonrpsee::RpcModule; -use std::collections::HashMap; pub fn register_methods(module: &mut RpcModule) { module - .register_method("object.services.get", get_map_thing!(object.services)) + .register_method("object.services.get", get_thing_by_name!(object.services)) .unwrap(); module - .register_method::, ApiError>, _>( + .register_method::, ApiError>, _>( "object.services.list", list_things!(object.services), ) @@ -24,27 +23,30 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "object.services.create", - create_map_thing!(object.services, Service), + create_thing!(object.services, Service), ) .unwrap(); module .register_method( "object.services.update", - update_map_thing!(object.services, Service), + update_thing_by_name!(object.services, Service), ) .unwrap(); module - .register_method("object.services.delete", delete_map_thing!(object.services)) + .register_method( + "object.services.delete", + delete_thing_by_name!(object.services), + ) .unwrap(); module - .register_method("object.addresses.get", get_map_thing!(object.addresses)) + .register_method("object.addresses.get", get_thing_by_name!(object.addresses)) .unwrap(); module - .register_method::, ApiError>, _>( + .register_method::, ApiError>, _>( "object.addresses.list", list_things!(object.addresses), ) @@ -53,21 +55,21 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "object.addresses.create", - create_map_thing!(object.addresses, Address), + create_thing!(object.addresses, Address), ) .unwrap(); module .register_method( "object.addresses.update", - update_map_thing!(object.addresses, Address), + update_thing_by_name!(object.addresses, Address), ) .unwrap(); module .register_method( "object.addresses.delete", - delete_map_thing!(object.addresses), + delete_thing_by_name!(object.addresses), ) .unwrap(); } diff --git a/src/api/service.rs b/src/api/service.rs index b94b05f..e45bfb8 100644 --- a/src/api/service.rs +++ b/src/api/service.rs @@ -1,10 +1,10 @@ use super::ApiError; use crate::{ - create_vec_thing, + create_thing, definitions::service::{DHCPServer, DNSServer, NTPServer}, - delete_vec_thing, get_vec_thing, list_things, + delete_thing_by_index, get_thing_by_index, list_things, state::RpcState, - update_vec_thing, + update_thing_by_index, }; use jsonrpsee::RpcModule; @@ -12,7 +12,7 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "service.dhcp_servers.get", - get_vec_thing!(service.dhcp_servers), + get_thing_by_index!(service.dhcp_servers), ) .unwrap(); @@ -26,28 +26,28 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "service.dhcp_servers.create", - create_vec_thing!(service.dhcp_servers, DHCPServer), + create_thing!(service.dhcp_servers, DHCPServer), ) .unwrap(); module .register_method( "service.dhcp_servers.update", - update_vec_thing!(service.dhcp_servers, DHCPServer), + update_thing_by_index!(service.dhcp_servers, DHCPServer), ) .unwrap(); module .register_method( "service.dhcp_servers.delete", - delete_vec_thing!(service.dhcp_servers), + delete_thing_by_index!(service.dhcp_servers), ) .unwrap(); module .register_method( "service.dns_servers.get", - get_vec_thing!(service.dns_servers), + get_thing_by_index!(service.dns_servers), ) .unwrap(); @@ -61,28 +61,28 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "service.dns_servers.create", - create_vec_thing!(service.dns_servers, DNSServer), + create_thing!(service.dns_servers, DNSServer), ) .unwrap(); module .register_method( "service.dns_servers.update", - update_vec_thing!(service.dns_servers, DNSServer), + update_thing_by_index!(service.dns_servers, DNSServer), ) .unwrap(); module .register_method( "service.dns_servers.delete", - delete_vec_thing!(service.dns_servers), + delete_thing_by_index!(service.dns_servers), ) .unwrap(); module .register_method( "service.ntp_servers.get", - get_vec_thing!(service.ntp_servers), + get_thing_by_index!(service.ntp_servers), ) .unwrap(); @@ -96,21 +96,21 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "service.ntp_servers.create", - create_vec_thing!(service.ntp_servers, NTPServer), + create_thing!(service.ntp_servers, NTPServer), ) .unwrap(); module .register_method( "service.ntp_servers.update", - update_vec_thing!(service.ntp_servers, NTPServer), + update_thing_by_index!(service.ntp_servers, NTPServer), ) .unwrap(); module .register_method( "service.ntp_servers.delete", - delete_vec_thing!(service.ntp_servers), + delete_thing_by_index!(service.ntp_servers), ) .unwrap(); } diff --git a/src/api/system.rs b/src/api/system.rs index 2f49699..4534d06 100644 --- a/src/api/system.rs +++ b/src/api/system.rs @@ -1,13 +1,11 @@ -use crate::config_manager::{ - Change, ChangeAction::Create, ChangeAction::Delete, ChangeAction::Update, -}; +use crate::config_manager::{Change, ChangeAction::Create, ChangeAction::Update}; +use crate::delete_thing_by_name; use crate::{definitions::system::User, state::RpcState}; use jsonrpsee::types::Params; use jsonrpsee::RpcModule; use pwhash::sha512_crypt; use serde::{Deserialize, Serialize}; -use ApiError::AlreadyExists; use ApiError::ConfigError; use ApiError::HashError; use ApiError::NotFound; @@ -35,7 +33,7 @@ pub fn register_methods(module: &mut RpcModule) { .unwrap(); module - .register_method("system.users.delete", delete_user) + .register_method("system.users.delete", delete_thing_by_name!(system.users)) .unwrap(); } @@ -47,22 +45,28 @@ pub struct GetUserResult { #[derive(Deserialize)] pub struct GetUser { - id: String, + name: String, } pub fn get_user(p: Params, state: &RpcState) -> Result { let u: GetUser = p.parse().map_err(ParameterDeserialize)?; - match state + let index = state .config_manager .get_pending_config() .system .users - .get(&u.id) - { - Some(user) => Ok(GetUserResult { - name: u.id, - comment: user.comment.clone(), + .iter() + .position(|e| *e.name == u.name); + + match index { + Some(i) => Ok(GetUserResult { + name: state.config_manager.get_pending_config().system.users[i] + .name + .clone(), + comment: state.config_manager.get_pending_config().system.users[i] + .comment + .clone(), }), None => Err(NotFound), } @@ -78,8 +82,8 @@ pub fn get_users(_: Params, state: &RpcState) -> Result, ApiE .iter() { res.push(GetUserResult { - name: u.0.to_string(), - comment: u.1.comment.clone(), + name: u.name.clone(), + comment: u.comment.clone(), }) } @@ -101,39 +105,27 @@ pub fn create_user(p: Params, state: &RpcState) -> Result<(), ApiError> { let mut cm = state.config_manager.clone(); let mut tx = cm.start_transaction(); - if tx - .config - .system - .users - .insert( - u.name.clone(), - User { - comment: match u.comment { - Some(c) => c, - None => "".to_string(), - }, - hash: hash, - }, - ) - .is_none() - { - tx.commit(Change { - action: Create, - path: USER_CHANGE_PATH, - id: u.name, - }) - .map_err(ConfigError) - } else { - tx.revert(); - Err(AlreadyExists) - } + tx.config.system.users.push(User { + name: u.name.clone(), + comment: match u.comment { + Some(c) => c, + None => "".to_string(), + }, + hash: hash, + }); + + tx.commit(Change { + action: Create, + path: USER_CHANGE_PATH, + id: u.name, + }) + .map_err(ConfigError) } #[derive(Deserialize)] struct UpdateUser { name: String, - password: String, - comment: Option, + thing: CreateUser, } pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> { @@ -142,25 +134,32 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> { let mut cm = state.config_manager.clone(); let mut tx = cm.start_transaction(); - match tx.config.system.users.get(&u.name) { - Some(user) => { - // Only Update Password if field is not empty - let hash = if u.password == "" { + let index = tx + .config + .system + .users + .iter() + .position(|e| *e.name == u.name); + + match index { + Some(i) => { + let user = &tx.config.system.users[i]; + + let hash = if u.thing.password == "" { user.hash.clone() } else { - sha512_crypt::hash(u.password).map_err(HashError)? + sha512_crypt::hash(u.thing.password).map_err(HashError)? }; - tx.config.system.users.insert( - u.name.clone(), - User { - comment: match u.comment { - Some(c) => c, - None => "".to_string(), - }, - hash, + tx.config.system.users[i] = User { + name: u.thing.name, + comment: match u.thing.comment { + Some(c) => c, + None => "".to_string(), }, - ); + hash, + }; + tx.commit(Change { action: Update, path: USER_CHANGE_PATH, @@ -171,29 +170,3 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> { None => Err(NotFound), } } - -#[derive(Deserialize)] -struct DeleteUser { - name: String, -} - -pub fn delete_user(p: Params, state: &RpcState) -> Result<(), ApiError> { - let u: DeleteUser = p.parse().map_err(ParameterDeserialize)?; - - let mut cm = state.config_manager.clone(); - let mut tx = cm.start_transaction(); - - match tx.config.system.users.remove(&u.name) { - Some(_) => tx - .commit(Change { - action: Delete, - path: USER_CHANGE_PATH, - id: u.name, - }) - .map_err(ConfigError), - None => { - tx.revert(); - Err(NotFound) - } - } -} diff --git a/src/api/vpn.rs b/src/api/vpn.rs index 9794bc1..0f47071 100644 --- a/src/api/vpn.rs +++ b/src/api/vpn.rs @@ -1,9 +1,9 @@ -use std::collections::HashMap; - use super::ApiError; use crate::definitions::vpn::{WireguardInterface, WireguardPeer}; use crate::state::RpcState; -use crate::{create_map_thing, delete_map_thing, get_map_thing, list_things, update_map_thing}; +use crate::{ + create_thing, delete_thing_by_name, get_thing_by_name, list_things, update_thing_by_name, +}; use jsonrpsee::types::Params; use jsonrpsee::RpcModule; @@ -15,12 +15,12 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "vpn.wireguard.interfaces.get", - get_map_thing!(vpn.wireguard.interfaces), + get_thing_by_name!(vpn.wireguard.interfaces), ) .unwrap(); module - .register_method::, ApiError>, _>( + .register_method::, ApiError>, _>( "vpn.wireguard.interfaces.list", list_things!(vpn.wireguard.interfaces), ) @@ -29,33 +29,33 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "vpn.wireguard.interfaces.create", - create_map_thing!(vpn.wireguard.interfaces, WireguardInterface), + create_thing!(vpn.wireguard.interfaces, WireguardInterface), ) .unwrap(); module .register_method( "vpn.wireguard.interfaces.update", - update_map_thing!(vpn.wireguard.interfaces, WireguardInterface), + update_thing_by_name!(vpn.wireguard.interfaces, WireguardInterface), ) .unwrap(); module .register_method( "vpn.wireguard.interfaces.delete", - delete_map_thing!(vpn.wireguard.interfaces), + delete_thing_by_name!(vpn.wireguard.interfaces), ) .unwrap(); module .register_method( "vpn.wireguard.peers.get", - get_map_thing!(vpn.wireguard.peers), + get_thing_by_name!(vpn.wireguard.peers), ) .unwrap(); module - .register_method::, ApiError>, _>( + .register_method::, ApiError>, _>( "vpn.wireguard.peers.list", list_things!(vpn.wireguard.peers), ) @@ -64,21 +64,21 @@ pub fn register_methods(module: &mut RpcModule) { module .register_method( "vpn.wireguard.peers.create", - create_map_thing!(vpn.wireguard.peers, WireguardPeer), + create_thing!(vpn.wireguard.peers, WireguardPeer), ) .unwrap(); module .register_method( "vpn.wireguard.peers.update", - update_map_thing!(vpn.wireguard.peers, WireguardPeer), + update_thing_by_name!(vpn.wireguard.peers, WireguardPeer), ) .unwrap(); module .register_method( "vpn.wireguard.peers.delete", - delete_map_thing!(vpn.wireguard.peers), + delete_thing_by_name!(vpn.wireguard.peers), ) .unwrap(); } diff --git a/src/config_manager.rs b/src/config_manager.rs index 86f0b52..b8c8e7e 100644 --- a/src/config_manager.rs +++ b/src/config_manager.rs @@ -151,12 +151,10 @@ pub fn generate_default_config(path: &str) -> Result<(), ConfigError> { let mut conf = Config::default(); let hash = sha512_crypt::hash("nfsense")?; conf.config_version = 1; - conf.system.users.insert( - "admin".to_string(), - crate::definitions::system::User { - comment: "Default Admin".to_string(), - hash: hash, - }, - ); + conf.system.users.push(crate::definitions::system::User { + name: "admin".to_string(), + comment: "Default Admin".to_string(), + hash: hash, + }); write_config_to_file(path, conf) } diff --git a/src/definitions/mod.rs b/src/definitions/mod.rs index 7909971..cb4dcf7 100644 --- a/src/definitions/mod.rs +++ b/src/definitions/mod.rs @@ -5,3 +5,17 @@ pub mod object; pub mod service; pub mod system; pub mod vpn; + +#[macro_export] +macro_rules! get_thing { + ($out:ty, $n:ident) => { + pub fn $n(list: Vec<$out>, name: String) -> Option<$out> { + for e in list { + if e.name == name { + return Some(e); + } + } + None + } + }; +} diff --git a/src/definitions/network.rs b/src/definitions/network.rs index 883f13d..fa8d1fe 100644 --- a/src/definitions/network.rs +++ b/src/definitions/network.rs @@ -1,22 +1,27 @@ use ipnet::IpNet; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, net::IpAddr}; +use std::net::IpAddr; use validator::Validate; +use crate::get_thing; + #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct Network { - pub interfaces: HashMap, + pub interfaces: Vec, pub static_routes: Vec, } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] pub struct NetworkInterface { + pub name: String, pub alias: String, pub comment: String, pub interface_type: NetworkInterfaceType, pub addressing_mode: AddressingMode, } +get_thing!(NetworkInterface, get_network_interface); + #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "snake_case")] pub enum NetworkInterfaceType { diff --git a/src/definitions/object.rs b/src/definitions/object.rs index eeb9225..14461dc 100644 --- a/src/definitions/object.rs +++ b/src/definitions/object.rs @@ -1,20 +1,25 @@ use ipnet::IpNet; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, net::IpAddr}; +use std::net::IpAddr; use validator::Validate; +use crate::get_thing; + #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct Object { - pub addresses: HashMap, - pub services: HashMap, + pub addresses: Vec
, + pub services: Vec, } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] pub struct Address { + pub name: String, pub address_type: AddressType, pub comment: String, } +get_thing!(Address, get_address); + #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "snake_case")] pub enum AddressType { @@ -26,10 +31,13 @@ pub enum AddressType { #[derive(Serialize, Deserialize, Clone, Validate, Debug)] pub struct Service { + pub name: String, pub service_type: ServiceType, pub comment: String, } +get_thing!(Service, get_service); + #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(rename_all = "lowercase")] pub enum ServiceType { diff --git a/src/definitions/system.rs b/src/definitions/system.rs index 48f01ff..6d9194e 100644 --- a/src/definitions/system.rs +++ b/src/definitions/system.rs @@ -1,14 +1,18 @@ use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use validator::Validate; +use crate::get_thing; + #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct System { - pub users: HashMap, + pub users: Vec, } #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct User { + pub name: String, pub comment: String, pub hash: String, } + +get_thing!(User, get_user); diff --git a/src/definitions/vpn.rs b/src/definitions/vpn.rs index 84104f7..2249ec3 100644 --- a/src/definitions/vpn.rs +++ b/src/definitions/vpn.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use validator::Validate; +use crate::get_thing; + #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct VPN { pub wireguard: Wireguard, @@ -9,12 +10,13 @@ pub struct VPN { #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] pub struct Wireguard { - pub interfaces: HashMap, - pub peers: HashMap, + pub interfaces: Vec, + pub peers: Vec, } #[derive(Serialize, Deserialize, Clone, Validate, Debug)] pub struct WireguardInterface { + pub name: String, pub public_key: String, pub private_key: String, pub listen_port: u64, @@ -22,8 +24,11 @@ pub struct WireguardInterface { pub comment: String, } +get_thing!(WireguardInterface, get_wireguard_interface); + #[derive(Serialize, Deserialize, Clone, Validate, Debug)] pub struct WireguardPeer { + pub name: String, pub public_key: String, pub preshared_key: Option, pub allowed_ips: Vec, @@ -31,3 +36,5 @@ pub struct WireguardPeer { pub persistent_keepalive: Option, pub comment: String, } + +get_thing!(WireguardPeer, get_wireguard_peer); diff --git a/src/web/auth.rs b/src/web/auth.rs index 0e8786e..879bd1c 100644 --- a/src/web/auth.rs +++ b/src/web/auth.rs @@ -4,6 +4,8 @@ use rbtag::BuildInfo; use std::sync::{Arc, RwLock}; use uuid::Uuid; +use crate::definitions::system::get_user; + use super::super::AppState; use axum::routing::post; use axum::{Json, Router}; @@ -64,13 +66,10 @@ async fn login_handler( State(state): State, Json(payload): Json, ) -> impl IntoResponse { - if let Some(user) = state - .config_manager - .get_current_config() - .system - .users - .get(&payload.username.to_string()) - { + if let Some(user) = get_user( + state.config_manager.get_current_config().system.users, + payload.username.to_string(), + ) { if sha512_crypt::verify(payload.password, &user.hash) { let mut sessions = state.session_state.sessions.write().unwrap(); let id = Uuid::new_v4().to_string();