Convert maps to vecs with name field

This commit is contained in:
Samuel Lorch 2023-11-06 02:34:34 +01:00
parent f5eb03cb16
commit 568d8cac5c
15 changed files with 305 additions and 316 deletions

View file

@ -12,14 +12,7 @@ let vm: any = $ref({});
async function create() { async function create() {
console.debug('value', vm); console.debug('value', vm);
let res: any; let res: any;
if (editTypes[subsystem][entity].idType == 'Number') { res = await apiCall(`${subsystem }.${entity}.create`, vm);
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});
}
if (res.Error === null) { if (res.Error === null) {
p.toast.success(`Created ${ editTypes[subsystem][entity].name}`); p.toast.success(`Created ${ editTypes[subsystem][entity].name}`);

View file

@ -1,10 +1,10 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_vec_thing, create_thing,
definitions::firewall::{DestinationNATRule, ForwardRule, SourceNATRule}, 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, state::RpcState,
update_vec_thing, update_thing_by_index,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -12,7 +12,7 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"firewall.forward_rules.get", "firewall.forward_rules.get",
get_vec_thing!(firewall.forward_rules), get_thing_by_index!(firewall.forward_rules),
) )
.unwrap(); .unwrap();
@ -26,28 +26,28 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"firewall.forward_rules.create", "firewall.forward_rules.create",
create_vec_thing!(firewall.forward_rules, ForwardRule), create_thing!(firewall.forward_rules, ForwardRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.forward_rules.update", "firewall.forward_rules.update",
update_vec_thing!(firewall.forward_rules, ForwardRule), update_thing_by_index!(firewall.forward_rules, ForwardRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.forward_rules.delete", "firewall.forward_rules.delete",
delete_vec_thing!(firewall.forward_rules), delete_thing_by_index!(firewall.forward_rules),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.destination_nat_rules.get", "firewall.destination_nat_rules.get",
get_vec_thing!(firewall.destination_nat_rules), get_thing_by_index!(firewall.destination_nat_rules),
) )
.unwrap(); .unwrap();
@ -61,28 +61,28 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"firewall.destination_nat_rules.create", "firewall.destination_nat_rules.create",
create_vec_thing!(firewall.destination_nat_rules, DestinationNATRule), create_thing!(firewall.destination_nat_rules, DestinationNATRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.destination_nat_rules.update", "firewall.destination_nat_rules.update",
update_vec_thing!(firewall.destination_nat_rules, DestinationNATRule), update_thing_by_index!(firewall.destination_nat_rules, DestinationNATRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.destination_nat_rules.delete", "firewall.destination_nat_rules.delete",
delete_vec_thing!(firewall.destination_nat_rules), delete_thing_by_index!(firewall.destination_nat_rules),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.source_nat_rules.get", "firewall.source_nat_rules.get",
get_vec_thing!(firewall.source_nat_rules), get_thing_by_index!(firewall.source_nat_rules),
) )
.unwrap(); .unwrap();
@ -96,21 +96,21 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"firewall.source_nat_rules.create", "firewall.source_nat_rules.create",
create_vec_thing!(firewall.source_nat_rules, SourceNATRule), create_thing!(firewall.source_nat_rules, SourceNATRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.source_nat_rules.update", "firewall.source_nat_rules.update",
update_vec_thing!(firewall.source_nat_rules, SourceNATRule), update_thing_by_index!(firewall.source_nat_rules, SourceNATRule),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.source_nat_rules.delete", "firewall.source_nat_rules.delete",
delete_vec_thing!(firewall.source_nat_rules), delete_thing_by_index!(firewall.source_nat_rules),
) )
.unwrap(); .unwrap();
} }

View file

@ -19,9 +19,8 @@ pub enum ApiError {
#[error("Not Found")] #[error("Not Found")]
NotFound, NotFound,
#[error("Already Exists")] //#[error("Already Exists")]
AlreadyExists, //AlreadyExists,
#[error("Hash Error")] #[error("Hash Error")]
HashError(#[from] pwhash::error::Error), HashError(#[from] pwhash::error::Error),
@ -44,50 +43,53 @@ impl Into<ErrorObject<'static>> for ApiError {
} }
#[macro_export] #[macro_export]
macro_rules! get_map_thing { macro_rules! get_thing_by_name {
($( $sub_system:ident ).+) => { ($( $sub_system:ident ).+) => {
|params, state| { |params, state| {
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
struct GetStringID { struct GetByName {
id: String, name: String,
} }
let t: GetStringID = params.parse().map_err(ApiError::ParameterDeserialize)?; let t: GetByName = params.parse().map_err(ApiError::ParameterDeserialize)?;
match state let index = state
.config_manager .config_manager
.get_pending_config() .get_pending_config()
.$($sub_system).+ .$($sub_system).+.iter().position(|e| *e.name == t.name);
.get(&t.id)
{ match index {
Some(thing) => Ok(thing.clone()), Some(i) => Ok(state
None => Err(ApiError::NotFound), .config_manager
.get_pending_config()
.$($sub_system).+[i].clone()),
None => Err(ApiError::NotFound)
} }
} }
}; };
} }
#[macro_export] #[macro_export]
macro_rules! get_vec_thing { macro_rules! get_thing_by_index {
($( $sub_system:ident ).+) => { ($( $sub_system:ident ).+) => {
|params, state| { |params, state| {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct GetIntID { struct GetByIndex {
id: i64, index: i64,
} }
let t: GetIntID = params.parse().map_err(ApiError::ParameterDeserialize)?; let t: GetByIndex = params.parse().map_err(ApiError::ParameterDeserialize)?;
let things = state let things = state
.config_manager .config_manager
.get_pending_config() .get_pending_config()
.$($sub_system).+; .$($sub_system).+;
if things.len() > t.id as usize { if things.len() > t.index as usize {
Ok(things[t.id as usize].clone()) Ok(things[t.index as usize].clone())
} else { } else {
Err(ApiError::NotFound) Err(ApiError::NotFound)
} }
@ -108,38 +110,7 @@ macro_rules! list_things {
} }
#[macro_export] #[macro_export]
macro_rules! create_map_thing { macro_rules! create_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 {
($( $sub_system:ident ).+, $typ:ty) => { ($( $sub_system:ident ).+, $typ:ty) => {
|params, state| { |params, state| {
let t: $typ = params.parse().map_err(ApiError::ParameterDeserialize)?; let t: $typ = params.parse().map_err(ApiError::ParameterDeserialize)?;
@ -160,93 +131,34 @@ macro_rules! create_vec_thing {
} }
#[macro_export] #[macro_export]
macro_rules! update_map_thing { macro_rules! update_thing_by_name {
($( $sub_system:ident ).+, $typ:ty) => { ($( $sub_system:ident ).+, $typ:ty) => {
|params, state| { |params, state| {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct CreateThing { struct UpdateByName {
id: String, name: String,
thing: $typ 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 cm = state.config_manager.clone();
let mut tx = cm.start_transaction(); let mut tx = cm.start_transaction();
if tx.config.$($sub_system).+.insert(t.id.clone(), t.thing).is_none() { let index = tx.config.$($sub_system).+.iter().position(|e| *e.name == t.name);
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)
}
}
};
}
#[macro_export] match index {
macro_rules! update_vec_thing { Some(i) => {
($( $sub_system:ident ).+, $typ:ty) => { tx.config.$($sub_system).+[i] = t.thing;
|params, state| {
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] tx.commit(crate::config_manager::Change {
struct CreateThing { action: crate::config_manager::ChangeAction::Update,
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,
path: stringify!($($sub_system).+), path: stringify!($($sub_system).+),
id: t.id, id: t.name,
}) })
.map_err(ApiError::ConfigError), .map_err(ApiError::ConfigError)
}
None => { None => {
tx.revert(); tx.revert();
Err(ApiError::NotFound) Err(ApiError::NotFound)
@ -257,27 +169,98 @@ macro_rules! delete_map_thing {
} }
#[macro_export] #[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 ).+) => { ($( $sub_system:ident ).+) => {
|params, state| { |params, state| {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct GetIntID { struct DeleteByName {
id: i64, 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 cm = state.config_manager.clone();
let mut tx = cm.start_transaction(); let mut tx = cm.start_transaction();
if tx.config.$($sub_system).+.len() > t.id as usize { let index = tx.config.$($sub_system).+.iter().position(|e| *e.name == t.name);
tx.config.$($sub_system).+.remove(t.id as usize);
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 { tx.commit(crate::config_manager::Change {
action: crate::config_manager::ChangeAction::Delete, action: crate::config_manager::ChangeAction::Delete,
path: stringify!($($sub_system).+), path: stringify!($($sub_system).+),
id: t.id.to_string(), id: t.index.to_string(),
}) })
.map_err(ApiError::ConfigError) .map_err(ApiError::ConfigError)
} else { } else {

View file

@ -1,19 +1,19 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_map_thing, create_vec_thing, create_thing,
definitions::network::{NetworkInterface, StaticRoute}, 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, state::RpcState,
update_map_thing, update_vec_thing, update_thing_by_index, update_thing_by_name,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
use std::collections::HashMap;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"network.static_routes.get", "network.static_routes.get",
get_vec_thing!(network.static_routes), get_thing_by_index!(network.static_routes),
) )
.unwrap(); .unwrap();
@ -27,30 +27,33 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"network.static_routes.create", "network.static_routes.create",
create_vec_thing!(network.static_routes, StaticRoute), create_thing!(network.static_routes, StaticRoute),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"network.static_routes.update", "network.static_routes.update",
update_vec_thing!(network.static_routes, StaticRoute), update_thing_by_index!(network.static_routes, StaticRoute),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"network.static_routes.delete", "network.static_routes.delete",
delete_vec_thing!(network.static_routes), delete_thing_by_index!(network.static_routes),
) )
.unwrap(); .unwrap();
module module
.register_method("network.interfaces.get", get_map_thing!(network.interfaces)) .register_method(
"network.interfaces.get",
get_thing_by_name!(network.interfaces),
)
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, NetworkInterface>, ApiError>, _>( .register_method::<Result<Vec<NetworkInterface>, ApiError>, _>(
"network.interfaces.list", "network.interfaces.list",
list_things!(network.interfaces), list_things!(network.interfaces),
) )
@ -59,21 +62,21 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"network.interfaces.create", "network.interfaces.create",
create_map_thing!(network.interfaces, NetworkInterface), create_thing!(network.interfaces, NetworkInterface),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"network.interfaces.update", "network.interfaces.update",
update_map_thing!(network.interfaces, NetworkInterface), update_thing_by_name!(network.interfaces, NetworkInterface),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"network.interfaces.delete", "network.interfaces.delete",
delete_map_thing!(network.interfaces), delete_thing_by_name!(network.interfaces),
) )
.unwrap(); .unwrap();
} }

View file

@ -1,21 +1,20 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_map_thing, create_thing,
definitions::object::{Address, Service}, definitions::object::{Address, Service},
delete_map_thing, get_map_thing, list_things, delete_thing_by_name, get_thing_by_name, list_things,
state::RpcState, state::RpcState,
update_map_thing, update_thing_by_name,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
use std::collections::HashMap;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method("object.services.get", get_map_thing!(object.services)) .register_method("object.services.get", get_thing_by_name!(object.services))
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, Service>, ApiError>, _>( .register_method::<Result<Vec<Service>, ApiError>, _>(
"object.services.list", "object.services.list",
list_things!(object.services), list_things!(object.services),
) )
@ -24,27 +23,30 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"object.services.create", "object.services.create",
create_map_thing!(object.services, Service), create_thing!(object.services, Service),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"object.services.update", "object.services.update",
update_map_thing!(object.services, Service), update_thing_by_name!(object.services, Service),
) )
.unwrap(); .unwrap();
module module
.register_method("object.services.delete", delete_map_thing!(object.services)) .register_method(
"object.services.delete",
delete_thing_by_name!(object.services),
)
.unwrap(); .unwrap();
module module
.register_method("object.addresses.get", get_map_thing!(object.addresses)) .register_method("object.addresses.get", get_thing_by_name!(object.addresses))
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, Address>, ApiError>, _>( .register_method::<Result<Vec<Address>, ApiError>, _>(
"object.addresses.list", "object.addresses.list",
list_things!(object.addresses), list_things!(object.addresses),
) )
@ -53,21 +55,21 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"object.addresses.create", "object.addresses.create",
create_map_thing!(object.addresses, Address), create_thing!(object.addresses, Address),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"object.addresses.update", "object.addresses.update",
update_map_thing!(object.addresses, Address), update_thing_by_name!(object.addresses, Address),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"object.addresses.delete", "object.addresses.delete",
delete_map_thing!(object.addresses), delete_thing_by_name!(object.addresses),
) )
.unwrap(); .unwrap();
} }

View file

@ -1,10 +1,10 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_vec_thing, create_thing,
definitions::service::{DHCPServer, DNSServer, NTPServer}, 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, state::RpcState,
update_vec_thing, update_thing_by_index,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -12,7 +12,7 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"service.dhcp_servers.get", "service.dhcp_servers.get",
get_vec_thing!(service.dhcp_servers), get_thing_by_index!(service.dhcp_servers),
) )
.unwrap(); .unwrap();
@ -26,28 +26,28 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"service.dhcp_servers.create", "service.dhcp_servers.create",
create_vec_thing!(service.dhcp_servers, DHCPServer), create_thing!(service.dhcp_servers, DHCPServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.dhcp_servers.update", "service.dhcp_servers.update",
update_vec_thing!(service.dhcp_servers, DHCPServer), update_thing_by_index!(service.dhcp_servers, DHCPServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.dhcp_servers.delete", "service.dhcp_servers.delete",
delete_vec_thing!(service.dhcp_servers), delete_thing_by_index!(service.dhcp_servers),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.dns_servers.get", "service.dns_servers.get",
get_vec_thing!(service.dns_servers), get_thing_by_index!(service.dns_servers),
) )
.unwrap(); .unwrap();
@ -61,28 +61,28 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"service.dns_servers.create", "service.dns_servers.create",
create_vec_thing!(service.dns_servers, DNSServer), create_thing!(service.dns_servers, DNSServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.dns_servers.update", "service.dns_servers.update",
update_vec_thing!(service.dns_servers, DNSServer), update_thing_by_index!(service.dns_servers, DNSServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.dns_servers.delete", "service.dns_servers.delete",
delete_vec_thing!(service.dns_servers), delete_thing_by_index!(service.dns_servers),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.ntp_servers.get", "service.ntp_servers.get",
get_vec_thing!(service.ntp_servers), get_thing_by_index!(service.ntp_servers),
) )
.unwrap(); .unwrap();
@ -96,21 +96,21 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"service.ntp_servers.create", "service.ntp_servers.create",
create_vec_thing!(service.ntp_servers, NTPServer), create_thing!(service.ntp_servers, NTPServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.ntp_servers.update", "service.ntp_servers.update",
update_vec_thing!(service.ntp_servers, NTPServer), update_thing_by_index!(service.ntp_servers, NTPServer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.ntp_servers.delete", "service.ntp_servers.delete",
delete_vec_thing!(service.ntp_servers), delete_thing_by_index!(service.ntp_servers),
) )
.unwrap(); .unwrap();
} }

View file

@ -1,13 +1,11 @@
use crate::config_manager::{ use crate::config_manager::{Change, ChangeAction::Create, ChangeAction::Update};
Change, ChangeAction::Create, ChangeAction::Delete, ChangeAction::Update, use crate::delete_thing_by_name;
};
use crate::{definitions::system::User, state::RpcState}; use crate::{definitions::system::User, state::RpcState};
use jsonrpsee::types::Params; use jsonrpsee::types::Params;
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
use pwhash::sha512_crypt; use pwhash::sha512_crypt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ApiError::AlreadyExists;
use ApiError::ConfigError; use ApiError::ConfigError;
use ApiError::HashError; use ApiError::HashError;
use ApiError::NotFound; use ApiError::NotFound;
@ -35,7 +33,7 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
.unwrap(); .unwrap();
module module
.register_method("system.users.delete", delete_user) .register_method("system.users.delete", delete_thing_by_name!(system.users))
.unwrap(); .unwrap();
} }
@ -47,22 +45,28 @@ pub struct GetUserResult {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetUser { pub struct GetUser {
id: String, name: String,
} }
pub fn get_user(p: Params, state: &RpcState) -> Result<GetUserResult, ApiError> { pub fn get_user(p: Params, state: &RpcState) -> Result<GetUserResult, ApiError> {
let u: GetUser = p.parse().map_err(ParameterDeserialize)?; let u: GetUser = p.parse().map_err(ParameterDeserialize)?;
match state let index = state
.config_manager .config_manager
.get_pending_config() .get_pending_config()
.system .system
.users .users
.get(&u.id) .iter()
{ .position(|e| *e.name == u.name);
Some(user) => Ok(GetUserResult {
name: u.id, match index {
comment: user.comment.clone(), 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), None => Err(NotFound),
} }
@ -78,8 +82,8 @@ pub fn get_users(_: Params, state: &RpcState) -> Result<Vec<GetUserResult>, ApiE
.iter() .iter()
{ {
res.push(GetUserResult { res.push(GetUserResult {
name: u.0.to_string(), name: u.name.clone(),
comment: u.1.comment.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 cm = state.config_manager.clone();
let mut tx = cm.start_transaction(); let mut tx = cm.start_transaction();
if tx tx.config.system.users.push(User {
.config name: u.name.clone(),
.system comment: match u.comment {
.users Some(c) => c,
.insert( None => "".to_string(),
u.name.clone(), },
User { hash: hash,
comment: match u.comment { });
Some(c) => c,
None => "".to_string(), tx.commit(Change {
}, action: Create,
hash: hash, path: USER_CHANGE_PATH,
}, id: u.name,
) })
.is_none() .map_err(ConfigError)
{
tx.commit(Change {
action: Create,
path: USER_CHANGE_PATH,
id: u.name,
})
.map_err(ConfigError)
} else {
tx.revert();
Err(AlreadyExists)
}
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct UpdateUser { struct UpdateUser {
name: String, name: String,
password: String, thing: CreateUser,
comment: Option<String>,
} }
pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> { 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 cm = state.config_manager.clone();
let mut tx = cm.start_transaction(); let mut tx = cm.start_transaction();
match tx.config.system.users.get(&u.name) { let index = tx
Some(user) => { .config
// Only Update Password if field is not empty .system
let hash = if u.password == "" { .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() user.hash.clone()
} else { } else {
sha512_crypt::hash(u.password).map_err(HashError)? sha512_crypt::hash(u.thing.password).map_err(HashError)?
}; };
tx.config.system.users.insert( tx.config.system.users[i] = User {
u.name.clone(), name: u.thing.name,
User { comment: match u.thing.comment {
comment: match u.comment { Some(c) => c,
Some(c) => c, None => "".to_string(),
None => "".to_string(),
},
hash,
}, },
); hash,
};
tx.commit(Change { tx.commit(Change {
action: Update, action: Update,
path: USER_CHANGE_PATH, path: USER_CHANGE_PATH,
@ -171,29 +170,3 @@ pub fn update_user(p: Params, state: &RpcState) -> Result<(), ApiError> {
None => Err(NotFound), 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)
}
}
}

View file

@ -1,9 +1,9 @@
use std::collections::HashMap;
use super::ApiError; use super::ApiError;
use crate::definitions::vpn::{WireguardInterface, WireguardPeer}; use crate::definitions::vpn::{WireguardInterface, WireguardPeer};
use crate::state::RpcState; 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::types::Params;
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -15,12 +15,12 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"vpn.wireguard.interfaces.get", "vpn.wireguard.interfaces.get",
get_map_thing!(vpn.wireguard.interfaces), get_thing_by_name!(vpn.wireguard.interfaces),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, WireguardInterface>, ApiError>, _>( .register_method::<Result<Vec<WireguardInterface>, ApiError>, _>(
"vpn.wireguard.interfaces.list", "vpn.wireguard.interfaces.list",
list_things!(vpn.wireguard.interfaces), list_things!(vpn.wireguard.interfaces),
) )
@ -29,33 +29,33 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"vpn.wireguard.interfaces.create", "vpn.wireguard.interfaces.create",
create_map_thing!(vpn.wireguard.interfaces, WireguardInterface), create_thing!(vpn.wireguard.interfaces, WireguardInterface),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.interfaces.update", "vpn.wireguard.interfaces.update",
update_map_thing!(vpn.wireguard.interfaces, WireguardInterface), update_thing_by_name!(vpn.wireguard.interfaces, WireguardInterface),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.interfaces.delete", "vpn.wireguard.interfaces.delete",
delete_map_thing!(vpn.wireguard.interfaces), delete_thing_by_name!(vpn.wireguard.interfaces),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.peers.get", "vpn.wireguard.peers.get",
get_map_thing!(vpn.wireguard.peers), get_thing_by_name!(vpn.wireguard.peers),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, WireguardPeer>, ApiError>, _>( .register_method::<Result<Vec<WireguardPeer>, ApiError>, _>(
"vpn.wireguard.peers.list", "vpn.wireguard.peers.list",
list_things!(vpn.wireguard.peers), list_things!(vpn.wireguard.peers),
) )
@ -64,21 +64,21 @@ pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"vpn.wireguard.peers.create", "vpn.wireguard.peers.create",
create_map_thing!(vpn.wireguard.peers, WireguardPeer), create_thing!(vpn.wireguard.peers, WireguardPeer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.peers.update", "vpn.wireguard.peers.update",
update_map_thing!(vpn.wireguard.peers, WireguardPeer), update_thing_by_name!(vpn.wireguard.peers, WireguardPeer),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.peers.delete", "vpn.wireguard.peers.delete",
delete_map_thing!(vpn.wireguard.peers), delete_thing_by_name!(vpn.wireguard.peers),
) )
.unwrap(); .unwrap();
} }

View file

@ -151,12 +151,10 @@ pub fn generate_default_config(path: &str) -> Result<(), ConfigError> {
let mut conf = Config::default(); let mut conf = Config::default();
let hash = sha512_crypt::hash("nfsense")?; let hash = sha512_crypt::hash("nfsense")?;
conf.config_version = 1; conf.config_version = 1;
conf.system.users.insert( conf.system.users.push(crate::definitions::system::User {
"admin".to_string(), name: "admin".to_string(),
crate::definitions::system::User { comment: "Default Admin".to_string(),
comment: "Default Admin".to_string(), hash: hash,
hash: hash, });
},
);
write_config_to_file(path, conf) write_config_to_file(path, conf)
} }

View file

@ -5,3 +5,17 @@ pub mod object;
pub mod service; pub mod service;
pub mod system; pub mod system;
pub mod vpn; 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
}
};
}

View file

@ -1,22 +1,27 @@
use ipnet::IpNet; use ipnet::IpNet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, net::IpAddr}; use std::net::IpAddr;
use validator::Validate; use validator::Validate;
use crate::get_thing;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct Network { pub struct Network {
pub interfaces: HashMap<String, NetworkInterface>, pub interfaces: Vec<NetworkInterface>,
pub static_routes: Vec<StaticRoute>, pub static_routes: Vec<StaticRoute>,
} }
#[derive(Serialize, Deserialize, Clone, Validate, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Debug)]
pub struct NetworkInterface { pub struct NetworkInterface {
pub name: String,
pub alias: String, pub alias: String,
pub comment: String, pub comment: String,
pub interface_type: NetworkInterfaceType, pub interface_type: NetworkInterfaceType,
pub addressing_mode: AddressingMode, pub addressing_mode: AddressingMode,
} }
get_thing!(NetworkInterface, get_network_interface);
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum NetworkInterfaceType { pub enum NetworkInterfaceType {

View file

@ -1,20 +1,25 @@
use ipnet::IpNet; use ipnet::IpNet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, net::IpAddr}; use std::net::IpAddr;
use validator::Validate; use validator::Validate;
use crate::get_thing;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct Object { pub struct Object {
pub addresses: HashMap<String, Address>, pub addresses: Vec<Address>,
pub services: HashMap<String, Service>, pub services: Vec<Service>,
} }
#[derive(Serialize, Deserialize, Clone, Validate, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Debug)]
pub struct Address { pub struct Address {
pub name: String,
pub address_type: AddressType, pub address_type: AddressType,
pub comment: String, pub comment: String,
} }
get_thing!(Address, get_address);
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum AddressType { pub enum AddressType {
@ -26,10 +31,13 @@ pub enum AddressType {
#[derive(Serialize, Deserialize, Clone, Validate, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Debug)]
pub struct Service { pub struct Service {
pub name: String,
pub service_type: ServiceType, pub service_type: ServiceType,
pub comment: String, pub comment: String,
} }
get_thing!(Service, get_service);
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum ServiceType { pub enum ServiceType {

View file

@ -1,14 +1,18 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use validator::Validate; use validator::Validate;
use crate::get_thing;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct System { pub struct System {
pub users: HashMap<String, User>, pub users: Vec<User>,
} }
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct User { pub struct User {
pub name: String,
pub comment: String, pub comment: String,
pub hash: String, pub hash: String,
} }
get_thing!(User, get_user);

View file

@ -1,7 +1,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use validator::Validate; use validator::Validate;
use crate::get_thing;
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct VPN { pub struct VPN {
pub wireguard: Wireguard, pub wireguard: Wireguard,
@ -9,12 +10,13 @@ pub struct VPN {
#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)]
pub struct Wireguard { pub struct Wireguard {
pub interfaces: HashMap<String, WireguardInterface>, pub interfaces: Vec<WireguardInterface>,
pub peers: HashMap<String, WireguardPeer>, pub peers: Vec<WireguardPeer>,
} }
#[derive(Serialize, Deserialize, Clone, Validate, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Debug)]
pub struct WireguardInterface { pub struct WireguardInterface {
pub name: String,
pub public_key: String, pub public_key: String,
pub private_key: String, pub private_key: String,
pub listen_port: u64, pub listen_port: u64,
@ -22,8 +24,11 @@ pub struct WireguardInterface {
pub comment: String, pub comment: String,
} }
get_thing!(WireguardInterface, get_wireguard_interface);
#[derive(Serialize, Deserialize, Clone, Validate, Debug)] #[derive(Serialize, Deserialize, Clone, Validate, Debug)]
pub struct WireguardPeer { pub struct WireguardPeer {
pub name: String,
pub public_key: String, pub public_key: String,
pub preshared_key: Option<String>, pub preshared_key: Option<String>,
pub allowed_ips: Vec<String>, pub allowed_ips: Vec<String>,
@ -31,3 +36,5 @@ pub struct WireguardPeer {
pub persistent_keepalive: Option<u64>, pub persistent_keepalive: Option<u64>,
pub comment: String, pub comment: String,
} }
get_thing!(WireguardPeer, get_wireguard_peer);

View file

@ -4,6 +4,8 @@ use rbtag::BuildInfo;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use uuid::Uuid; use uuid::Uuid;
use crate::definitions::system::get_user;
use super::super::AppState; use super::super::AppState;
use axum::routing::post; use axum::routing::post;
use axum::{Json, Router}; use axum::{Json, Router};
@ -64,13 +66,10 @@ async fn login_handler(
State(state): State<AppState>, State(state): State<AppState>,
Json(payload): Json<LoginParameters>, Json(payload): Json<LoginParameters>,
) -> impl IntoResponse { ) -> impl IntoResponse {
if let Some(user) = state if let Some(user) = get_user(
.config_manager state.config_manager.get_current_config().system.users,
.get_current_config() payload.username.to_string(),
.system ) {
.users
.get(&payload.username.to_string())
{
if sha512_crypt::verify(payload.password, &user.hash) { if sha512_crypt::verify(payload.password, &user.hash) {
let mut sessions = state.session_state.sessions.write().unwrap(); let mut sessions = state.session_state.sessions.write().unwrap();
let id = Uuid::new_v4().to_string(); let id = Uuid::new_v4().to_string();