From 93cdb17ccfadd67cf5ba8fc083b96e4d52e6be7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 30 Jan 2026 07:29:33 +0100 Subject: [PATCH 1/3] Separate API for Alias and Destination --- Cargo.lock | 40 +-- .../defguard_common/src/db/models/device.rs | 4 +- .../src/db/models/wireguard.rs | 4 +- .../src/enterprise/db/models/acl.rs | 253 ++++++------------ .../src/enterprise/handlers/acl.rs | 56 +--- .../src/enterprise/handlers/acl/alias.rs | 182 ++++++++++++- .../enterprise/handlers/acl/destination.rs | 203 ++++++++++++-- .../defguard_core/src/grpc/gateway/handler.rs | 4 +- .../src/handlers/component_setup.rs | 2 +- .../tests/integration/api/acl.rs | 11 +- crates/defguard_event_router/src/lib.rs | 2 +- crates/defguard_session_manager/src/lib.rs | 2 +- .../src/session_state.rs | 2 +- .../src/vpn_session_stats.rs | 2 +- 14 files changed, 483 insertions(+), 284 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 335981a003..6c7a531cc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,9 +691,9 @@ checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18" [[package]] name = "clap" -version = "4.5.55" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e34525d5bbbd55da2bb745d34b36121baac88d07619a9a09cfcf4a6c0832785" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" dependencies = [ "clap_builder", "clap_derive", @@ -701,9 +701,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.55" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a20016a20a3da95bef50ec7238dbd09baeef4311dcdd38ec15aba69812fb61" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" dependencies = [ "anstream", "anstyle", @@ -2439,9 +2439,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -5781,9 +5781,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "a286e33f82f8a1ee2df63f4fa35c0becf4a85a0cb03091a15fd7bf0b402dc94a" dependencies = [ "async-trait", "axum", @@ -5813,9 +5813,9 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40aaccc9f9eccf2cd82ebc111adc13030d23e887244bc9cfa5d1d636049de3" +checksum = "27aac809edf60b741e2d7db6367214d078856b8a5bff0087e94ff330fb97b6fc" dependencies = [ "prettyplease", "proc-macro2", @@ -5825,9 +5825,9 @@ dependencies = [ [[package]] name = "tonic-health" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a82868bf299e0a1d2e8dce0dc33a46c02d6f045b2c1f1d6cc8dc3d0bf1812ef" +checksum = "8dbde2c702c4be12b9b2f6f7e6c824a84a7b7be177070cada8ee575a581af359" dependencies = [ "prost", "tokio", @@ -5838,9 +5838,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "d6c55a2d6a14174563de34409c9f92ff981d006f56da9c6ecd40d9d4a31500b0" dependencies = [ "bytes", "prost", @@ -5849,9 +5849,9 @@ dependencies = [ [[package]] name = "tonic-prost-build" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a16cba4043dc3ff43fcb3f96b4c5c154c64cbd18ca8dce2ab2c6a451d058a2" +checksum = "a4556786613791cfef4ed134aa670b61a85cfcacf71543ef33e8d801abae988f" dependencies = [ "prettyplease", "proc-macro2", @@ -6957,18 +6957,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.35" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" +checksum = "dafd85c832c1b68bbb4ec0c72c7f6f4fc5179627d2bc7c26b30e4c0cc11e76cc" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.35" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" +checksum = "7cb7e4e8436d9db52fbd6625dbf2f45243ab84994a72882ec8227b99e72b439a" dependencies = [ "proc-macro2", "quote", diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs index dfbf670997..53aa3abbff 100644 --- a/crates/defguard_common/src/db/models/device.rs +++ b/crates/defguard_common/src/db/models/device.rs @@ -38,10 +38,10 @@ pub struct DeviceConfig { pub network_id: Id, pub network_name: String, pub config: String, - #[schema(value_type = String)] + #[schema(value_type = Vec)] pub address: Vec, pub endpoint: String, - #[schema(value_type = String)] + #[schema(value_type = Vec)] pub allowed_ips: Vec, pub pubkey: String, pub dns: Option, diff --git a/crates/defguard_common/src/db/models/wireguard.rs b/crates/defguard_common/src/db/models/wireguard.rs index 6dddd4b162..dc334769af 100644 --- a/crates/defguard_common/src/db/models/wireguard.rs +++ b/crates/defguard_common/src/db/models/wireguard.rs @@ -109,7 +109,7 @@ pub struct WireguardNetwork { pub id: I, pub name: String, #[model(ref)] - #[schema(value_type = String)] + #[schema(value_type = Vec)] pub address: Vec, pub port: i32, // Should be u16 pub pubkey: String, @@ -120,7 +120,7 @@ pub struct WireguardNetwork { pub mtu: i32, // Should be u32, but sqlx won't allow that. pub fwmark: i64, // Should be u32, but sqlx won't allow that. #[model(ref)] - #[schema(value_type = String)] + #[schema(value_type = Vec)] pub allowed_ips: Vec, pub connected_at: Option, pub acl_enabled: bool, diff --git a/crates/defguard_core/src/enterprise/db/models/acl.rs b/crates/defguard_core/src/enterprise/db/models/acl.rs index 8a5885e017..cd884bf571 100644 --- a/crates/defguard_core/src/enterprise/db/models/acl.rs +++ b/crates/defguard_core/src/enterprise/db/models/acl.rs @@ -28,7 +28,9 @@ use crate::{ appstate::AppState, enterprise::{ firewall::{FirewallError, try_get_location_firewall_config}, - handlers::acl::{ApiAclAlias, ApiAclRule, EditAclAlias, EditAclRule}, + handlers::acl::{ + ApiAclRule, EditAclRule, alias::EditAclAlias, destination::EditAclDestination, + }, }, grpc::gateway::events::GatewayEvent, }; @@ -73,7 +75,7 @@ pub type Protocol = i32; /// Representation of port range. Those are stored in the db as [`PgRange`]. /// Single ports are represented as single-element ranges, e.g. port 80 = PortRange(80, 80) /// since upper bound is excluded by convention. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct PortRange(pub RangeInclusive); impl fmt::Display for PortRange { @@ -142,7 +144,7 @@ impl From for PgRange { /// Applied state does NOT guarantee that all locations have received the rule /// and performed appropriate operations, only that the next time configuration /// is being sent it will include this rule. -#[derive(Clone, Debug, Default, Deserialize, Serialize, Type, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Serialize, PartialEq, ToSchema, Type)] #[sqlx(type_name = "aclrule_state", rename_all = "lowercase")] pub enum RuleState { #[default] @@ -235,7 +237,7 @@ impl AclRuleInfo { /// Those objects have their dedicated tables and structures so we provide /// [`AclRuleInfo`] and [`ApiAclRule`] structs that implement appropriate methods /// to combine all the related objects for easier downstream processing. -#[derive(Clone, Debug, Default, Model, PartialEq, Eq, FromRow)] +#[derive(Clone, Debug, Default, Eq, FromRow, Model, PartialEq, ToSchema)] pub struct AclRule { pub id: I, // if present points to the original rule before modification / deletion @@ -249,8 +251,10 @@ pub struct AclRule { pub deny_all_network_devices: bool, pub all_networks: bool, #[model(ref)] + #[schema(value_type = Vec)] pub destination: Vec, #[model(ref)] + #[schema(value_type = Vec)] pub ports: Vec>, #[model(ref)] pub protocols: Vec, @@ -515,15 +519,15 @@ impl AclRule { } #[derive(Debug, Default)] -pub struct ParsedDestination { +pub(crate) struct ParsedDestination { addrs: Vec, - ranges: Vec<(IpAddr, IpAddr)>, + pub(crate) ranges: Vec<(IpAddr, IpAddr)>, } /// Perses a destination string into singular ip addresses or networks and address /// ranges. We should be able to parse a string like this one: /// `10.0.0.1/24, 10.1.1.10-10.1.1.20, 192.168.1.10, 10.1.1.1-10.10.1.1` -pub fn parse_destination(destination: &str) -> Result { +pub(crate) fn parse_destination(destination: &str) -> Result { debug!("Parsing destination string: {destination}"); let destination: String = destination.chars().filter(|c| !c.is_whitespace()).collect(); let mut result = ParsedDestination::default(); @@ -1340,17 +1344,19 @@ impl AclRuleInfo { } } -/// Helper struct combining all DB objects related to given [`AclAlias`]. +/// Helper struct combining all database objects related to given [`AclAlias`]. /// All related objects are stored in vectors. -#[derive(Clone, Debug)] -pub(crate) struct AclAliasInfo { - pub id: I, +#[derive(Clone, Debug, ToSchema)] +pub(crate) struct AclAliasInfo { + pub id: Id, pub parent_id: Option, pub name: String, pub kind: AliasKind, pub state: AliasState, + #[schema(value_type = Vec)] pub destination: Vec, pub destination_ranges: Vec>, + #[schema(value_type = Vec)] pub ports: Vec, pub protocols: Vec, pub rules: Vec>, @@ -1359,7 +1365,7 @@ pub(crate) struct AclAliasInfo { pub any_protocol: bool, } -impl AclAliasInfo { +impl AclAliasInfo { /// Constructs a [`String`] of comma-separated addresses and address ranges pub(crate) fn format_destination(&self) -> String { // process single addresses @@ -1404,7 +1410,7 @@ impl AclAliasInfo { /// since they do not cause any changes to locations until they /// are used by a rule. /// `Deleted` state is also omitted since we don't allow deleting if an alias is used by any rules. -#[derive(Clone, Debug, Default, Deserialize, Serialize, Type, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize, ToSchema, Type)] #[sqlx(type_name = "aclalias_state", rename_all = "lowercase")] pub enum AliasState { #[default] @@ -1414,7 +1420,8 @@ pub enum AliasState { /// ACL alias can be of one of the following types: /// - Destination: the alias defines a complete destination that an ACL rule applies to -/// - Component: the alias defines parts of a destination and will be combined with other parts manually defined in an ACL rule +/// - Component: the alias defines parts of a destination and will be combined with other parts +/// manually defined in an ACL rule #[derive(Clone, Debug, Default, Deserialize, Eq, Serialize, PartialEq, ToSchema, Type)] #[sqlx(type_name = "aclalias_kind", rename_all = "lowercase")] pub enum AliasKind { @@ -1477,115 +1484,6 @@ impl AclAlias { } } - /// Try to convert alias from API. - pub(crate) fn try_from(alias: &EditAclAlias, kind: AliasKind) -> Result { - Ok(Self { - destination: parse_destination(&alias.destination)?.addrs, - ports: parse_ports(&alias.ports)? - .into_iter() - .map(Into::into) - .collect(), - id: NoId, - parent_id: None, - name: alias.name.clone(), - kind, - state: AliasState::Applied, - protocols: alias.protocols.clone(), - any_destination: alias.any_destination, - any_port: alias.any_port, - any_protocol: alias.any_protocol, - }) - } - - /// Creates new [`AclAlias`] with all related objects based on [`AclAliasInfo`]. - pub(crate) async fn create_from_api( - pool: &PgPool, - api_alias: &EditAclAlias, - kind: AliasKind, - ) -> Result { - let mut transaction = pool.begin().await?; - - // save the alias - let alias = AclAlias::try_from(api_alias, kind)? - .save(&mut *transaction) - .await?; - - // create related objects - Self::create_related_objects(&mut transaction, alias.id, api_alias).await?; - - transaction.commit().await?; - let result = ApiAclAlias::from(alias.to_info(pool).await?); - Ok(result) - } - - /// Updates [`AclAlias`] with all it's related objects based on [`AclAliasInfo`] - pub(crate) async fn update_from_api( - pool: &PgPool, - id: Id, - api_alias: &EditAclAlias, - kind: AliasKind, - ) -> Result { - let mut transaction = pool.begin().await?; - - // find existing alias - let existing_alias = AclAlias::find_by_id(&mut *transaction, id) - .await? - .ok_or_else(|| { - warn!("Update of nonexistent alias ({id}) failed"); - AclError::AliasNotFoundError(id) - })?; - - // Convert alias from API to model. - let mut alias = AclAlias::try_from(api_alias, kind)?; - - // perform appropriate updates depending on existing alias' state - let alias = match existing_alias.state { - AliasState::Applied => { - // create new `AliasState::Modified` alias - debug!("Alias {id} state is `Applied` - creating new `Modified` alias object",); - // remove old modifications of this alias - let result = query!("DELETE FROM aclalias WHERE parent_id = $1", id) - .execute(&mut *transaction) - .await?; - debug!( - "Removed {} old modifications of alias {id}", - result.rows_affected(), - ); - - // save as a new alias with appropriate parent_id and state - alias.state = AliasState::Modified; - alias.parent_id = Some(id); - let alias = alias.save(&mut *transaction).await?; - - // create related objects - AclAlias::::create_related_objects(&mut transaction, alias.id, api_alias) - .await?; - - alias - } - AliasState::Modified => { - debug!( - "Alias {id} is a modification to alias {:?} - updating the modification", - existing_alias.parent_id, - ); - // update the not-yet applied modification itself - let mut alias = alias.with_id(id); - alias.parent_id = existing_alias.parent_id; - alias.save(&mut *transaction).await?; - - // recreate related objects - Self::delete_related_objects(&mut transaction, alias.id).await?; - AclAlias::::create_related_objects(&mut transaction, alias.id, api_alias) - .await?; - - alias - } - }; - - transaction.commit().await?; - Ok(alias.to_info(pool).await?.into()) - } - /// Deletes [`AclAlias`] with all it's related objects. /// /// State handling: @@ -1631,7 +1529,7 @@ impl AclAlias { } // delete related objects - Self::delete_related_objects(&mut transaction, id).await?; + acl_delete_related_objects(&mut transaction, id).await?; // delete the alias itself existing_alias.delete(&mut *transaction).await?; @@ -1709,53 +1607,74 @@ impl AclAlias { } } -impl AclAlias { - /// Creates relation objects for a given [`AclAlias`] based on [`AclAliasInfo`] object. - async fn create_related_objects( - transaction: &mut PgConnection, - alias_id: Id, - api_alias: &EditAclAlias, - ) -> Result<(), AclError> { - debug!("Creating related objects for ACL alias {api_alias:?}"); - // save related destination ranges - let destination = parse_destination(&api_alias.destination)?; - for range in destination.ranges { - let obj = AclAliasDestinationRange { - id: NoId, - alias_id, - start: range.0, - end: range.1, - }; - obj.save(&mut *transaction).await?; - } +impl TryFrom<&EditAclAlias> for AclAlias { + type Error = AclError; - info!("Created related objects for ACL alias {api_alias:?}"); - Ok(()) + fn try_from(alias: &EditAclAlias) -> Result { + Ok(Self { + destination: parse_destination(&alias.destination)?.addrs, + ports: parse_ports(&alias.ports)? + .into_iter() + .map(Into::into) + .collect(), + id: NoId, + parent_id: None, + name: alias.name.clone(), + kind: AliasKind::Component, + state: AliasState::Applied, + protocols: alias.protocols.clone(), + any_destination: true, + any_port: true, + any_protocol: true, + }) } +} - /// Deletes relation objects for a given [`AclAlias`]. - async fn delete_related_objects( - transaction: &mut PgConnection, - alias_id: Id, - ) -> Result<(), AclError> { - debug!("Deleting related objects for ACL alias {alias_id}"); - // destination ranges - let result = query!( - "DELETE FROM aclaliasdestinationrange WHERE alias_id = $1", - alias_id - ) - .execute(&mut *transaction) - .await?; - debug!( - "Deleted {} aclaliasdestinationrange records related to alias {alias_id}", - result.rows_affected() - ); +impl TryFrom<&EditAclDestination> for AclAlias { + type Error = AclError; - info!("Deleted related objects for ACL alias {alias_id}"); - Ok(()) + fn try_from(alias: &EditAclDestination) -> Result { + Ok(Self { + destination: parse_destination(&alias.destination)?.addrs, + ports: parse_ports(&alias.ports)? + .into_iter() + .map(Into::into) + .collect(), + id: NoId, + parent_id: None, + name: alias.name.clone(), + kind: AliasKind::Destination, + state: AliasState::Applied, + protocols: alias.protocols.clone(), + any_destination: alias.any_destination, + any_port: alias.any_port, + any_protocol: alias.any_protocol, + }) } } +/// Deletes relation objects for a given [`AclAlias`]. +pub(crate) async fn acl_delete_related_objects( + transaction: &mut PgConnection, + alias_id: Id, +) -> Result<(), AclError> { + debug!("Deleting related objects for ACL alias {alias_id}"); + // destination ranges + let result = query!( + "DELETE FROM aclaliasdestinationrange WHERE alias_id = $1", + alias_id + ) + .execute(&mut *transaction) + .await?; + debug!( + "Deleted {} aclaliasdestinationrange records related to alias {alias_id}", + result.rows_affected() + ); + + info!("Deleted related objects for ACL alias {alias_id}"); + Ok(()) +} + impl AclAlias { /// Returns all [`AclAliasDestinationRanges`]es the alias applies to pub(crate) async fn get_destination_ranges<'e, E>( @@ -1798,7 +1717,7 @@ impl AclAlias { /// Retrieves all related objects from the db and converts [`AclAlias`] /// instance to [`AclAliasInfo`]. - pub(crate) async fn to_info(&self, pool: &PgPool) -> Result, SqlxError> { + pub(crate) async fn to_info(&self, pool: &PgPool) -> Result { let destination_ranges = self.get_destination_ranges(pool).await?; let rules = self.get_rules(pool).await?; @@ -1947,11 +1866,13 @@ impl From<&AclRuleDestinationRange> for RangeInclusive { } } -#[derive(Clone, Debug, Deserialize, PartialEq)] +#[derive(Clone, Debug, Deserialize, PartialEq, ToSchema)] pub(crate) struct AclAliasDestinationRange { pub id: I, pub alias_id: Id, + #[schema(value_type = String)] pub start: IpAddr, + #[schema(value_type = String)] pub end: IpAddr, } diff --git a/crates/defguard_core/src/enterprise/handlers/acl.rs b/crates/defguard_core/src/enterprise/handlers/acl.rs index 4cecdca3e7..b9192d60e9 100644 --- a/crates/defguard_core/src/enterprise/handlers/acl.rs +++ b/crates/defguard_core/src/enterprise/handlers/acl.rs @@ -1,4 +1,4 @@ -pub(crate) mod alias; +pub mod alias; pub(crate) mod destination; use axum::{ @@ -15,9 +15,7 @@ use super::LicenseInfo; use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, - enterprise::db::models::acl::{ - AclAlias, AclAliasInfo, AclRule, AclRuleInfo, AliasKind, AliasState, Protocol, RuleState, - }, + enterprise::db::models::acl::{AclAlias, AclRule, AclRuleInfo, Protocol, RuleState}, error::WebError, handlers::{ApiResponse, ApiResult}, }; @@ -163,56 +161,6 @@ impl From> for EditAclRule { } } -/// API representation of [`AclAlias`] -/// All relations represented as arrays of ids. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct ApiAclAlias { - #[serde(default)] - pub id: Id, - pub parent_id: Option, - pub name: String, - pub kind: AliasKind, - pub state: AliasState, - pub destination: String, - pub ports: String, - pub protocols: Vec, - pub rules: Vec, - pub any_destination: bool, - pub any_port: bool, - pub any_protocol: bool, -} - -impl From> for ApiAclAlias { - fn from(info: AclAliasInfo) -> Self { - Self { - destination: info.format_destination(), - ports: info.format_ports(), - id: info.id, - parent_id: info.parent_id, - name: info.name, - kind: info.kind, - state: info.state, - protocols: info.protocols, - rules: info.rules.iter().map(|v| v.id).collect(), - any_destination: info.any_destination, - any_port: info.any_port, - any_protocol: info.any_protocol, - } - } -} - -/// API representation of [`AclAlias`] used in API requests for modification operations -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, ToSchema)] -pub struct EditAclAlias { - pub name: String, - pub destination: String, - pub ports: String, - pub protocols: Vec, - pub any_destination: bool, - pub any_port: bool, - pub any_protocol: bool, -} - #[derive(Debug, Deserialize, ToSchema)] pub struct ApplyAclRulesData { rules: Vec, diff --git a/crates/defguard_core/src/enterprise/handlers/acl/alias.rs b/crates/defguard_core/src/enterprise/handlers/acl/alias.rs index e6ba76e96c..a5201a6a44 100644 --- a/crates/defguard_core/src/enterprise/handlers/acl/alias.rs +++ b/crates/defguard_core/src/enterprise/handlers/acl/alias.rs @@ -3,24 +3,186 @@ use axum::{ extract::{Path, State}, http::StatusCode, }; -use defguard_common::db::Id; +use defguard_common::db::{Id, NoId}; use serde_json::{Value, json}; +use sqlx::{PgConnection, PgPool, query}; +use utoipa::ToSchema; -use super::{ApiAclAlias, EditAclAlias, LicenseInfo}; +use super::LicenseInfo; use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, - enterprise::db::models::acl::{AclAlias, AliasKind}, + enterprise::db::models::acl::{ + AclAlias, AclAliasDestinationRange, AclAliasInfo, AclError, AliasKind, AliasState, + Protocol, acl_delete_related_objects, parse_destination, + }, handlers::{ApiResponse, ApiResult}, }; +/// API representation of [`AclAlias`] used in API requests for modification operations. +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, ToSchema)] +pub struct EditAclAlias { + pub name: String, + pub destination: String, + pub ports: String, + pub protocols: Vec, +} + +impl EditAclAlias { + /// Creates relation objects for a given [`AclAlias`] based on [`AclAliasInfo`] object. + pub(crate) async fn create_related_objects( + &self, + transaction: &mut PgConnection, + alias_id: Id, + ) -> Result<(), AclError> { + debug!("Creating related objects for ACL alias {self:?}"); + // save related destination ranges + let destination = parse_destination(&self.destination)?; + for range in destination.ranges { + let obj = AclAliasDestinationRange { + id: NoId, + alias_id, + start: range.0, + end: range.1, + }; + obj.save(&mut *transaction).await?; + } + + info!("Created related objects for ACL alias {self:?}"); + Ok(()) + } +} + +/// API representation of [`AclAlias`] for "Alias Component" (not "Destination"). +/// All relations represented as arrays of IDs. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, ToSchema)] +pub struct ApiAclAlias { + #[serde(default)] + pub id: Id, + pub parent_id: Option, + pub name: String, + pub kind: AliasKind, + pub state: AliasState, + pub destination: String, + pub ports: String, + pub protocols: Vec, + pub rules: Vec, +} + +impl ApiAclAlias { + /// Creates new [`AclAlias`] with all related objects based on [`AclAliasInfo`]. + pub(crate) async fn create_from_api( + pool: &PgPool, + api_alias: &EditAclAlias, + ) -> Result { + let mut transaction = pool.begin().await?; + + let alias = AclAlias::try_from(api_alias)? + .save(&mut *transaction) + .await?; + + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + transaction.commit().await?; + let result = Self::from(alias.to_info(pool).await?); + Ok(result) + } + + /// Updates [`AclAlias`] with all it's related objects based on [`AclAliasInfo`]. + pub(crate) async fn update_from_api( + pool: &PgPool, + id: Id, + api_alias: &EditAclAlias, + ) -> Result { + let mut transaction = pool.begin().await?; + + // find existing alias + let existing_alias = AclAlias::find_by_id(&mut *transaction, id) + .await? + .ok_or_else(|| { + warn!("Update of nonexistent alias ({id}) failed"); + AclError::AliasNotFoundError(id) + })?; + + // Convert alias from API to model. + let mut alias = AclAlias::try_from(api_alias)?; + + // perform appropriate updates depending on existing alias' state + let alias = match existing_alias.state { + AliasState::Applied => { + // create new `AliasState::Modified` alias + debug!("Alias {id} state is `Applied` - creating new `Modified` alias object",); + // remove old modifications of this alias + let result = query!("DELETE FROM aclalias WHERE parent_id = $1", id) + .execute(&mut *transaction) + .await?; + debug!( + "Removed {} old modifications of alias {id}", + result.rows_affected(), + ); + + // save as a new alias with appropriate parent_id and state + alias.state = AliasState::Modified; + alias.parent_id = Some(id); + let alias = alias.save(&mut *transaction).await?; + + // create related objects + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + alias + } + AliasState::Modified => { + debug!( + "Alias {id} is a modification to alias {:?} - updating the modification", + existing_alias.parent_id, + ); + // update the not-yet applied modification itself + let mut alias = alias.with_id(id); + alias.parent_id = existing_alias.parent_id; + alias.save(&mut *transaction).await?; + + // recreate related objects + acl_delete_related_objects(&mut transaction, alias.id).await?; + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + alias + } + }; + + transaction.commit().await?; + Ok(alias.to_info(pool).await?.into()) + } +} + +impl From for ApiAclAlias { + fn from(info: AclAliasInfo) -> Self { + Self { + destination: info.format_destination(), + ports: info.format_ports(), + id: info.id, + parent_id: info.parent_id, + name: info.name, + kind: info.kind, + state: info.state, + protocols: info.protocols, + rules: info.rules.iter().map(|v| v.id).collect(), + } + } +} + /// List all ACL aliases. #[utoipa::path( get, path = "/api/v1/acl/alias", tag = "ACL", responses( - (status = OK, description = "ACL alias"), + (status = OK, description = "ACL alias", body = Vec), ), )] pub(crate) async fn list_acl_aliases( @@ -31,7 +193,7 @@ pub(crate) async fn list_acl_aliases( ) -> ApiResult { debug!("User {} listing ACL aliases", session.user.username); let aliases = AclAlias::all(&appstate.pool).await?; - let mut api_aliases: Vec = Vec::with_capacity(aliases.len()); + let mut api_aliases = Vec::::with_capacity(aliases.len()); for alias in &aliases { // TODO: may require optimisation wrt. sql queries let info = alias.to_info(&appstate.pool).await.map_err(|err| { @@ -56,7 +218,7 @@ pub(crate) async fn list_acl_aliases( ("id" = Id, Path, description = "ID of ACL alias",) ), responses( - (status = OK, description = "ACL alias"), + (status = OK, description = "ACL alias", body = ApiAclAlias), ) )] pub(crate) async fn get_acl_alias( @@ -94,7 +256,7 @@ pub(crate) async fn get_acl_alias( tag = "ACL", request_body = EditAclAlias, responses( - (status = CREATED, description = "ACL alias"), + (status = CREATED, description = "ACL alias", body = ApiAclAlias), ) )] pub(crate) async fn create_acl_alias( @@ -105,7 +267,7 @@ pub(crate) async fn create_acl_alias( Json(data): Json, ) -> ApiResult { debug!("User {} creating ACL alias {data:?}", session.user.username); - let alias = AclAlias::create_from_api(&appstate.pool, &data, AliasKind::Component) + let alias = ApiAclAlias::create_from_api(&appstate.pool, &data) .await .map_err(|err| { error!("Error creating ACL alias {data:?}: {err}"); @@ -131,7 +293,7 @@ pub(crate) async fn create_acl_alias( ), request_body = EditAclAlias, responses( - (status = OK, description = "ACL alias"), + (status = OK, description = "ACL alias", body = ApiAclAlias), ) )] pub(crate) async fn update_acl_alias( @@ -143,7 +305,7 @@ pub(crate) async fn update_acl_alias( Json(data): Json, ) -> ApiResult { debug!("User {} updating ACL alias {data:?}", session.user.username); - let alias = AclAlias::update_from_api(&appstate.pool, id, &data, AliasKind::Component) + let alias = ApiAclAlias::update_from_api(&appstate.pool, id, &data) .await .map_err(|err| { error!("Error updating ACL alias {data:?}: {err}"); diff --git a/crates/defguard_core/src/enterprise/handlers/acl/destination.rs b/crates/defguard_core/src/enterprise/handlers/acl/destination.rs index ecda97c003..3b56902e23 100644 --- a/crates/defguard_core/src/enterprise/handlers/acl/destination.rs +++ b/crates/defguard_core/src/enterprise/handlers/acl/destination.rs @@ -2,25 +2,196 @@ use axum::{ Json, extract::{Path, State}, }; -use defguard_common::db::Id; +use defguard_common::db::{Id, NoId}; use reqwest::StatusCode; use serde_json::{Value, json}; +use sqlx::{PgConnection, PgPool, query}; +use utoipa::ToSchema; -use super::{ApiAclAlias, EditAclAlias, LicenseInfo}; +use super::LicenseInfo; use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, - enterprise::db::models::acl::{AclAlias, AliasKind}, + enterprise::db::models::acl::{ + AclAlias, AclAliasDestinationRange, AclAliasInfo, AclError, AliasKind, AliasState, + Protocol, acl_delete_related_objects, parse_destination, + }, handlers::{ApiResponse, ApiResult}, }; +/// API representation of [`AclAlias`] used in API requests for modification operations +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, ToSchema)] +pub struct EditAclDestination { + pub name: String, + pub destination: String, + pub ports: String, + pub protocols: Vec, + pub any_destination: bool, + pub any_port: bool, + pub any_protocol: bool, +} + +impl EditAclDestination { + /// Creates relation objects for a given [`AclAlias`] based on [`AclAliasInfo`] object. + pub(crate) async fn create_related_objects( + &self, + transaction: &mut PgConnection, + alias_id: Id, + ) -> Result<(), AclError> { + debug!("Creating related objects for ACL alias {self:?}"); + // save related destination ranges + let destination = parse_destination(&self.destination)?; + for range in destination.ranges { + let obj = AclAliasDestinationRange { + id: NoId, + alias_id, + start: range.0, + end: range.1, + }; + obj.save(&mut *transaction).await?; + } + + info!("Created related objects for ACL alias {self:?}"); + Ok(()) + } +} + +/// API representation of [`AclAlias`] for "Destination" (not "Alias Component"). +/// All relations represented as arrays of IDs. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, ToSchema)] +pub(crate) struct ApiAclDestination { + #[serde(default)] + pub id: Id, + pub parent_id: Option, + pub name: String, + pub kind: AliasKind, + pub state: AliasState, + pub destination: String, + pub ports: String, + pub protocols: Vec, + pub rules: Vec, + pub any_destination: bool, + pub any_port: bool, + pub any_protocol: bool, +} + +impl ApiAclDestination { + /// Creates new [`AclAlias`] with all related objects based on [`AclAliasInfo`]. + pub(crate) async fn create_from_api( + pool: &PgPool, + api_alias: &EditAclDestination, + ) -> Result { + let mut transaction = pool.begin().await?; + + let alias = AclAlias::try_from(api_alias)? + .save(&mut *transaction) + .await?; + + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + transaction.commit().await?; + let result = Self::from(alias.to_info(pool).await?); + Ok(result) + } + + /// Updates [`AclAlias`] with all it's related objects based on [`AclAliasInfo`]. + pub(crate) async fn update_from_api( + pool: &PgPool, + id: Id, + api_alias: &EditAclDestination, + ) -> Result { + let mut transaction = pool.begin().await?; + + // find existing alias + let existing_alias = AclAlias::find_by_id(&mut *transaction, id) + .await? + .ok_or_else(|| { + warn!("Update of nonexistent alias ({id}) failed"); + AclError::AliasNotFoundError(id) + })?; + + // Convert alias from API to model. + let mut alias = AclAlias::try_from(api_alias)?; + + // perform appropriate updates depending on existing alias' state + let alias = match existing_alias.state { + AliasState::Applied => { + // create new `AliasState::Modified` alias + debug!("Alias {id} state is `Applied` - creating new `Modified` alias object",); + // remove old modifications of this alias + let result = query!("DELETE FROM aclalias WHERE parent_id = $1", id) + .execute(&mut *transaction) + .await?; + debug!( + "Removed {} old modifications of alias {id}", + result.rows_affected(), + ); + + // save as a new alias with appropriate parent_id and state + alias.state = AliasState::Modified; + alias.parent_id = Some(id); + let alias = alias.save(&mut *transaction).await?; + + // create related objects + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + alias + } + AliasState::Modified => { + debug!( + "Alias {id} is a modification to alias {:?} - updating the modification", + existing_alias.parent_id, + ); + // update the not-yet applied modification itself + let mut alias = alias.with_id(id); + alias.parent_id = existing_alias.parent_id; + alias.save(&mut *transaction).await?; + + // recreate related objects + acl_delete_related_objects(&mut transaction, alias.id).await?; + api_alias + .create_related_objects(&mut transaction, alias.id) + .await?; + + alias + } + }; + + transaction.commit().await?; + Ok(alias.to_info(pool).await?.into()) + } +} + +impl From for ApiAclDestination { + fn from(info: AclAliasInfo) -> Self { + Self { + destination: info.format_destination(), + ports: info.format_ports(), + id: info.id, + parent_id: info.parent_id, + name: info.name, + kind: info.kind, + state: info.state, + protocols: info.protocols, + rules: info.rules.iter().map(|v| v.id).collect(), + any_destination: info.any_destination, + any_port: info.any_port, + any_protocol: info.any_protocol, + } + } +} + /// List ACL destinations. #[utoipa::path( get, path = "/api/v1/acl/destination", tag = "ACL", responses( - (status = OK, description = "ACL destination"), + (status = OK, description = "ACL destination", body = Vec), ) )] pub(crate) async fn list_acl_destinations( @@ -31,7 +202,7 @@ pub(crate) async fn list_acl_destinations( ) -> ApiResult { debug!("User {} listing ACL destinations", session.user.username); let aliases = AclAlias::all(&appstate.pool).await?; - let mut api_aliases: Vec = Vec::with_capacity(aliases.len()); + let mut api_aliases = Vec::::with_capacity(aliases.len()); for alias in &aliases { // TODO: may require optimisation wrt. sql queries let info = alias.to_info(&appstate.pool).await.map_err(|err| { @@ -53,10 +224,10 @@ pub(crate) async fn list_acl_destinations( path = "/api/v1/acl/destination/{id}", tag = "ACL", params( - ("id" = Id, Path, description = "ID of ACL destination",) + ("id" = Id, Path, description = "ID of ACL destination") ), responses( - (status = OK, description = "ACL destination"), + (status = OK, description = "ACL destination", body = ApiAclDestination), ) )] pub(crate) async fn get_acl_destination( @@ -72,7 +243,7 @@ pub(crate) async fn get_acl_destination( ); let (alias, status) = match AclAlias::find_by_id(&appstate.pool, id).await? { Some(alias) => ( - json!(ApiAclAlias::from( + json!(ApiAclDestination::from( alias.to_info(&appstate.pool).await.map_err(|err| { error!("Error retrieving ACL destination {alias:?}: {err}"); err @@ -98,9 +269,9 @@ pub(crate) async fn get_acl_destination( post, path = "/api/v1/acl/destination", tag = "ACL", - request_body = EditAclAlias, + request_body = EditAclDestination, responses( - (status = CREATED, description = "ACL destination"), + (status = CREATED, description = "ACL destination", body = ApiAclDestination), ) )] pub(crate) async fn create_acl_destination( @@ -108,13 +279,13 @@ pub(crate) async fn create_acl_destination( _admin: AdminRole, State(appstate): State, session: SessionInfo, - Json(data): Json, + Json(data): Json, ) -> ApiResult { debug!( "User {} creating ACL destination {data:?}", session.user.username ); - let alias = AclAlias::create_from_api(&appstate.pool, &data, AliasKind::Destination) + let alias = ApiAclDestination::create_from_api(&appstate.pool, &data) .await .map_err(|err| { error!("Error creating ACL destination {data:?}: {err}"); @@ -139,7 +310,7 @@ pub(crate) async fn create_acl_destination( ("id" = Id, Path, description = "ID of ACL destination",) ), responses( - (status = OK, description = "ACL destination"), + (status = OK, description = "ACL destination", body = ApiAclDestination), ) )] pub(crate) async fn update_acl_destination( @@ -148,13 +319,13 @@ pub(crate) async fn update_acl_destination( State(appstate): State, session: SessionInfo, Path(id): Path, - Json(data): Json, + Json(data): Json, ) -> ApiResult { debug!( "User {} updating ACL destination {data:?}", session.user.username ); - let alias = AclAlias::update_from_api(&appstate.pool, id, &data, AliasKind::Destination) + let alias = ApiAclDestination::update_from_api(&appstate.pool, id, &data) .await .map_err(|err| { error!("Error updating ACL destination {data:?}: {err}"); @@ -184,7 +355,7 @@ pub(crate) async fn delete_acl_destination( _admin: AdminRole, State(appstate): State, session: SessionInfo, - Path(id): Path, + Path(id): Path, ) -> ApiResult { debug!( "User {} deleting ACL destination {id}", diff --git a/crates/defguard_core/src/grpc/gateway/handler.rs b/crates/defguard_core/src/grpc/gateway/handler.rs index 4aa617099e..0e0219a3d1 100644 --- a/crates/defguard_core/src/grpc/gateway/handler.rs +++ b/crates/defguard_core/src/grpc/gateway/handler.rs @@ -422,9 +422,9 @@ impl GatewayHandler { "Failed to send peers stats update to session manager: {err}" ); continue; - }; + } } - }; + } // Save stats to database. // FIXME: remove once legacy table is removed diff --git a/crates/defguard_core/src/handlers/component_setup.rs b/crates/defguard_core/src/handlers/component_setup.rs index ef5dc0cc9f..050c6689e1 100644 --- a/crates/defguard_core/src/handlers/component_setup.rs +++ b/crates/defguard_core/src/handlers/component_setup.rs @@ -920,7 +920,7 @@ pub async fn setup_gateway_tls_stream( if let Err(err) = gateway.save(&appstate.pool).await { yield Ok(flow.error(&format!("Failed to save Gateway to database: {err}"))); return; - }; + } debug!("Gateway setup completed successfully"); diff --git a/crates/defguard_core/tests/integration/api/acl.rs b/crates/defguard_core/tests/integration/api/acl.rs index 22f8632631..c85f9603c7 100644 --- a/crates/defguard_core/tests/integration/api/acl.rs +++ b/crates/defguard_core/tests/integration/api/acl.rs @@ -13,7 +13,10 @@ use defguard_common::{ use defguard_core::{ enterprise::{ db::models::acl::{AclAlias, AclRule, AliasKind, AliasState, RuleState}, - handlers::acl::{ApiAclAlias, ApiAclRule, EditAclAlias, EditAclRule}, + handlers::acl::{ + ApiAclRule, EditAclRule, + alias::{ApiAclAlias, EditAclAlias}, + }, license::{get_cached_license, set_cached_license}, }, handlers::Auth, @@ -84,9 +87,6 @@ fn make_alias() -> EditAclAlias { destination: "10.2.2.2, 10.0.0.1/24, 10.0.10.1-10.0.20.1".to_string(), protocols: vec![6, 17], ports: "1, 2, 3, 10-20, 30-40".to_string(), - any_destination: true, - any_port: true, - any_protocol: true, } } @@ -143,9 +143,6 @@ fn edit_alias_data_into_api_response( ports: data.ports, protocols: data.protocols, rules, - any_destination: data.any_destination, - any_port: data.any_port, - any_protocol: data.any_protocol, } } diff --git a/crates/defguard_event_router/src/lib.rs b/crates/defguard_event_router/src/lib.rs index 132f56d754..8a69b650e0 100644 --- a/crates/defguard_event_router/src/lib.rs +++ b/crates/defguard_event_router/src/lib.rs @@ -138,7 +138,7 @@ impl EventRouter { Event::Bidi(bidi_event) => self.handle_bidi_event(bidi_event)?, Event::Internal(internal_event) => self.handle_internal_event(*internal_event)?, Event::SessionManager(session_manager_event) => { - self.handle_session_manager_event(*session_manager_event)? + self.handle_session_manager_event(*session_manager_event)?; } } } diff --git a/crates/defguard_session_manager/src/lib.rs b/crates/defguard_session_manager/src/lib.rs index 31563e1f6c..86e90c9fb7 100644 --- a/crates/defguard_session_manager/src/lib.rs +++ b/crates/defguard_session_manager/src/lib.rs @@ -142,7 +142,7 @@ impl SessionManager { if let Some(session) = maybe_session { // update session stats session.update_stats(transaction, message).await?; - }; + } trace!("Finished processing peer stats update"); Ok(()) diff --git a/crates/defguard_session_manager/src/session_state.rs b/crates/defguard_session_manager/src/session_state.rs index 422a830d75..70431b565a 100644 --- a/crates/defguard_session_manager/src/session_state.rs +++ b/crates/defguard_session_manager/src/session_state.rs @@ -265,7 +265,7 @@ impl ActiveSessionsMap { "Received peer stats update for an inactive peer. Skipping creating a new session..." ); return Ok(None); - }; + } // fetch other related objects from DB // clone them because we'll need those for event context diff --git a/tools/defguard_generator/src/vpn_session_stats.rs b/tools/defguard_generator/src/vpn_session_stats.rs index 7e62eb98c9..696b74fd43 100644 --- a/tools/defguard_generator/src/vpn_session_stats.rs +++ b/tools/defguard_generator/src/vpn_session_stats.rs @@ -141,7 +141,7 @@ async fn prepare_gateway(pool: &PgPool, location_id: Id) -> Result> match existing_gateways.into_iter().next() { Some(gateway) => Ok(gateway), None => { - let gateway = Gateway::new(location_id, "http://localhost:50055") + let gateway = Gateway::new(location_id, "http://localhost:50055", "gateway") .save(pool) .await?; Ok(gateway) From 00d0d888d59a0dc91ca0a2ccfbc2cd462015998e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 30 Jan 2026 07:50:09 +0100 Subject: [PATCH 2/3] Reduce visibility --- crates/defguard_core/src/enterprise/db/models/acl.rs | 5 ++--- crates/defguard_core/src/enterprise/handlers/acl.rs | 4 ++-- .../defguard_core/src/enterprise/handlers/acl/destination.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/defguard_core/src/enterprise/db/models/acl.rs b/crates/defguard_core/src/enterprise/db/models/acl.rs index cd884bf571..9d6d2a3bda 100644 --- a/crates/defguard_core/src/enterprise/db/models/acl.rs +++ b/crates/defguard_core/src/enterprise/db/models/acl.rs @@ -1543,7 +1543,7 @@ impl AclAlias { /// # Errors /// /// - `AclError::AliasNotFoundError` - pub async fn apply_aliases(aliases: &[Id], appstate: &AppState) -> Result<(), AclError> { + pub(crate) async fn apply_aliases(aliases: &[Id], appstate: &AppState) -> Result<(), AclError> { debug!("Applying {} ACL aliases: {aliases:?}", aliases.len()); let mut transaction = appstate.pool.begin().await?; @@ -1576,8 +1576,7 @@ impl AclAlias { } } - let affected_locations: Vec> = - affected_locations.into_iter().collect(); + let affected_locations = affected_locations.into_iter().collect::>(); debug!( "{} locations affected by applied ACL aliases. Sending gateway firewall update events \ for each location", diff --git a/crates/defguard_core/src/enterprise/handlers/acl.rs b/crates/defguard_core/src/enterprise/handlers/acl.rs index b9192d60e9..59e3e6e229 100644 --- a/crates/defguard_core/src/enterprise/handlers/acl.rs +++ b/crates/defguard_core/src/enterprise/handlers/acl.rs @@ -162,12 +162,12 @@ impl From> for EditAclRule { } #[derive(Debug, Deserialize, ToSchema)] -pub struct ApplyAclRulesData { +pub(crate) struct ApplyAclRulesData { rules: Vec, } #[derive(Debug, Deserialize, ToSchema)] -pub struct ApplyAclAliasesData { +pub(crate) struct ApplyAclAliasesData { aliases: Vec, } diff --git a/crates/defguard_core/src/enterprise/handlers/acl/destination.rs b/crates/defguard_core/src/enterprise/handlers/acl/destination.rs index 3b56902e23..844ce1e5c7 100644 --- a/crates/defguard_core/src/enterprise/handlers/acl/destination.rs +++ b/crates/defguard_core/src/enterprise/handlers/acl/destination.rs @@ -21,7 +21,7 @@ use crate::{ /// API representation of [`AclAlias`] used in API requests for modification operations #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, ToSchema)] -pub struct EditAclDestination { +pub(crate) struct EditAclDestination { pub name: String, pub destination: String, pub ports: String, From fc80fc6eb836da65e072416452bd41f5f8c3005e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 30 Jan 2026 08:57:42 +0100 Subject: [PATCH 3/3] Cleanup --- .../src/enterprise/db/models/acl.rs | 193 ++++++------ .../src/enterprise/db/models/acl/tests.rs | 198 ++++-------- .../src/enterprise/firewall/tests.rs | 284 +++++++----------- .../defguard_core/src/grpc/gateway/handler.rs | 5 +- 4 files changed, 284 insertions(+), 396 deletions(-) diff --git a/crates/defguard_core/src/enterprise/db/models/acl.rs b/crates/defguard_core/src/enterprise/db/models/acl.rs index 9d6d2a3bda..63b20c0b5b 100644 --- a/crates/defguard_core/src/enterprise/db/models/acl.rs +++ b/crates/defguard_core/src/enterprise/db/models/acl.rs @@ -610,12 +610,8 @@ impl AclRule { // save related networks debug!("Creating related networks for ACL rule {rule_id}"); for network_id in &api_rule.networks { - let obj = AclRuleNetwork { - id: NoId, - rule_id, - network_id: *network_id, - }; - obj.save(&mut *transaction) + AclRuleNetwork::new(rule_id, *network_id) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "WireguardNetwork", *network_id))?; } @@ -623,13 +619,8 @@ impl AclRule { // allowed users debug!("Creating related allowed users for ACL rule {rule_id}"); for user_id in &api_rule.allowed_users { - let obj = AclRuleUser { - id: NoId, - allow: true, - rule_id, - user_id: *user_id, - }; - obj.save(&mut *transaction) + AclRuleUser::new(rule_id, *user_id, true) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "User", *user_id))?; } @@ -637,13 +628,8 @@ impl AclRule { // denied users debug!("Creating related denied users for ACL rule {rule_id}"); for user_id in &api_rule.denied_users { - let obj = AclRuleUser { - id: NoId, - allow: false, - rule_id, - user_id: *user_id, - }; - obj.save(&mut *transaction) + AclRuleUser::new(rule_id, *user_id, false) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "User", *user_id))?; } @@ -651,13 +637,8 @@ impl AclRule { // allowed groups debug!("Creating related allowed groups for ACL rule {rule_id}"); for group_id in &api_rule.allowed_groups { - let obj = AclRuleGroup { - id: NoId, - allow: true, - rule_id, - group_id: *group_id, - }; - obj.save(&mut *transaction) + AclRuleGroup::new(rule_id, *group_id, true) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "Group", *group_id))?; } @@ -665,13 +646,8 @@ impl AclRule { // denied groups debug!("Creating related denied groups for ACL rule {rule_id}"); for group_id in &api_rule.denied_groups { - let obj = AclRuleGroup { - id: NoId, - allow: false, - rule_id, - group_id: *group_id, - }; - obj.save(&mut *transaction) + AclRuleGroup::new(rule_id, *group_id, false) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "Group", *group_id))?; } @@ -697,12 +673,8 @@ impl AclRule { )); } for alias_id in &api_rule.aliases { - let obj = AclRuleAlias { - id: NoId, - rule_id, - alias_id: *alias_id, - }; - obj.save(&mut *transaction) + AclRuleAlias::new(rule_id, *alias_id) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "AclAlias", *alias_id))?; } @@ -710,13 +682,8 @@ impl AclRule { // allowed devices debug!("Creating related allowed devices for ACL rule {rule_id}"); for device_id in &api_rule.allowed_devices { - let obj = AclRuleDevice { - id: NoId, - allow: true, - rule_id, - device_id: *device_id, - }; - obj.save(&mut *transaction) + AclRuleDevice::new(rule_id, *device_id, true) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "Device", *device_id))?; } @@ -724,13 +691,8 @@ impl AclRule { // denied devices debug!("Creating related denied devices for ACL rule {rule_id}"); for device_id in &api_rule.denied_devices { - let obj = AclRuleDevice { - id: NoId, - allow: false, - rule_id, - device_id: *device_id, - }; - obj.save(&mut *transaction) + AclRuleDevice::new(rule_id, *device_id, false) + .save(&mut *transaction) .await .map_err(|err| map_relation_error(err, "Device", *device_id))?; } @@ -1789,45 +1751,108 @@ impl AclAlias { } } -#[derive(Clone, Debug, Model, PartialEq)] -pub struct AclRuleNetwork { - pub id: I, - pub rule_id: Id, - pub network_id: Id, +#[derive(Model)] +pub(crate) struct AclRuleNetwork { + #[allow(dead_code)] + id: I, + rule_id: Id, + network_id: Id, } -#[derive(Clone, Debug, Model, PartialEq)] -pub struct AclRuleUser { - pub id: I, - pub rule_id: Id, - pub user_id: Id, - pub allow: bool, +impl AclRuleNetwork { + #[must_use] + pub(crate) fn new(rule_id: Id, network_id: Id) -> Self { + Self { + id: NoId, + rule_id, + network_id, + } + } } -#[derive(Clone, Debug, Model, PartialEq)] -pub struct AclRuleGroup { - pub id: I, - pub rule_id: Id, - pub group_id: Id, - pub allow: bool, +#[derive(Model)] +pub(crate) struct AclRuleUser { + #[allow(dead_code)] + id: I, + rule_id: Id, + user_id: Id, + allow: bool, } -#[derive(Clone, Debug, Model, PartialEq)] -pub struct AclRuleAlias { - pub id: I, - pub rule_id: Id, - pub alias_id: Id, +impl AclRuleUser { + #[must_use] + pub(crate) fn new(rule_id: Id, user_id: Id, allow: bool) -> Self { + Self { + id: NoId, + rule_id, + user_id, + allow, + } + } } -#[derive(Clone, Debug, Model, PartialEq)] -pub struct AclRuleDevice { - pub id: I, - pub rule_id: Id, - pub device_id: Id, - pub allow: bool, +#[derive(Model)] +pub(crate) struct AclRuleGroup { + #[allow(dead_code)] + id: I, + rule_id: Id, + group_id: Id, + allow: bool, +} + +impl AclRuleGroup { + #[must_use] + pub(crate) fn new(rule_id: Id, group_id: Id, allow: bool) -> Self { + Self { + id: NoId, + rule_id, + group_id, + allow, + } + } +} + +#[derive(Model)] +pub(crate) struct AclRuleAlias { + #[allow(dead_code)] + id: I, + rule_id: Id, + alias_id: Id, +} + +impl AclRuleAlias { + #[must_use] + pub(crate) fn new(rule_id: Id, alias_id: Id) -> Self { + Self { + id: NoId, + rule_id, + alias_id, + } + } +} + +#[derive(Model)] +pub(crate) struct AclRuleDevice { + #[allow(dead_code)] + id: I, + rule_id: Id, + device_id: Id, + allow: bool, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +impl AclRuleDevice { + #[must_use] + pub(crate) fn new(rule_id: Id, device_id: Id, allow: bool) -> Self { + Self { + id: NoId, + rule_id, + device_id, + allow, + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct AclRuleDestinationRange { pub id: I, pub rule_id: Id, @@ -1835,7 +1860,7 @@ pub struct AclRuleDestinationRange { pub end: IpAddr, } -impl AclRuleDestinationRange { +impl AclRuleDestinationRange { pub async fn save<'e, E>(self, executor: E) -> Result, SqlxError> where E: PgExecutor<'e>, diff --git a/crates/defguard_core/src/enterprise/db/models/acl/tests.rs b/crates/defguard_core/src/enterprise/db/models/acl/tests.rs index 29bd3691b3..119639c5fc 100644 --- a/crates/defguard_core/src/enterprise/db/models/acl/tests.rs +++ b/crates/defguard_core/src/enterprise/db/models/acl/tests.rs @@ -82,44 +82,22 @@ async fn test_allow_conflicting_sources(_: PgPoolOptions, options: PgConnectOpti .save(&pool) .await .unwrap(); - let _ = AclRuleUser { - id: NoId, - rule_id: rule.id, - user_id: user.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); - let result = AclRuleUser { - id: NoId, - rule_id: rule.id, - user_id: user.id, - allow: false, - } - .save(&pool) - .await; + AclRuleUser::new(rule.id, user.id, true) + .save(&pool) + .await + .unwrap(); + let result = AclRuleUser::new(rule.id, user.id, false).save(&pool).await; assert!(result.is_ok()); // group let group = Group::new("group1").save(&pool).await.unwrap(); - let _ = AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); - let result = AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group.id, - allow: false, - } - .save(&pool) - .await; + AclRuleGroup::new(rule.id, group.id, true) + .save(&pool) + .await + .unwrap(); + let result = AclRuleGroup::new(rule.id, group.id, false) + .save(&pool) + .await; assert!(result.is_ok()); // device @@ -134,23 +112,13 @@ async fn test_allow_conflicting_sources(_: PgPoolOptions, options: PgConnectOpti .save(&pool) .await .unwrap(); - let _ = AclRuleDevice { - id: NoId, - rule_id: rule.id, - device_id: device.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); - let result = AclRuleDevice { - id: NoId, - rule_id: rule.id, - device_id: device.id, - allow: false, - } - .save(&pool) - .await; + AclRuleDevice::new(rule.id, device.id, true) + .save(&pool) + .await + .unwrap(); + let result = AclRuleDevice::new(rule.id, device.id, false) + .save(&pool) + .await; assert!(result.is_ok()); } @@ -224,14 +192,10 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { .unwrap(); // rule only applied to network1 - let _rn = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: network1.id, - } - .save(&pool) - .await - .unwrap(); + AclRuleNetwork::new(rule.id, network1.id) + .save(&pool) + .await + .unwrap(); // create 2 users let mut user1 = User::new("user1", None, "", "", "u1@mail.com", None) @@ -244,52 +208,32 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { .unwrap(); // user1 allowed - let _ru1 = AclRuleUser { - id: NoId, - rule_id: rule.id, - user_id: user1.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); + AclRuleUser::new(rule.id, user1.id, true) + .save(&pool) + .await + .unwrap(); // user2 denied - let mut ru2 = AclRuleUser { - id: NoId, - rule_id: rule.id, - user_id: user2.id, - allow: false, - } - .save(&pool) - .await - .unwrap(); + let mut ru2 = AclRuleUser::new(rule.id, user2.id, false) + .save(&pool) + .await + .unwrap(); // create 2 grups let group1 = Group::new("group1").save(&pool).await.unwrap(); let group2 = Group::new("group2").save(&pool).await.unwrap(); // group1 allowed - let _rg = AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group1.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); + AclRuleGroup::new(rule.id, group1.id, true) + .save(&pool) + .await + .unwrap(); // group2 denied - let _rg = AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group2.id, - allow: false, - } - .save(&pool) - .await - .unwrap(); + AclRuleGroup::new(rule.id, group2.id, false) + .save(&pool) + .await + .unwrap(); // create 2 devices let device1 = Device::new( @@ -316,26 +260,16 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { .unwrap(); // device1 allowed - let _rd = AclRuleDevice { - id: NoId, - rule_id: rule.id, - device_id: device1.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); + AclRuleDevice::new(rule.id, device1.id, true) + .save(&pool) + .await + .unwrap(); // device2 denied - let _rd = AclRuleDevice { - id: NoId, - rule_id: rule.id, - device_id: device2.id, - allow: false, - } - .save(&pool) - .await - .unwrap(); + AclRuleDevice::new(rule.id, device2.id, false) + .save(&pool) + .await + .unwrap(); // create 2 aliases let alias1 = AclAlias::new( @@ -368,14 +302,10 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { .unwrap(); // only alias1 applies to the rule - let _ra = AclRuleAlias { - id: NoId, - rule_id: rule.id, - alias_id: alias1.id, - } - .save(&pool) - .await - .unwrap(); + AclRuleAlias::new(rule.id, alias1.id) + .save(&pool) + .await + .unwrap(); let mut conn = pool.acquire().await.unwrap(); @@ -582,15 +512,10 @@ async fn test_all_allowed_users(_: PgPoolOptions, options: PgConnectOptions) { .await .unwrap(); - AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group_2.id, - allow: true, - } - .save(&pool) - .await - .unwrap(); + AclRuleGroup::new(rule.id, group_2.id, true) + .save(&pool) + .await + .unwrap(); // Get rule info let mut conn = pool.acquire().await.unwrap(); @@ -710,15 +635,10 @@ async fn test_all_denied_users(_: PgPoolOptions, options: PgConnectOptions) { .await .unwrap(); - AclRuleGroup { - id: NoId, - rule_id: rule.id, - group_id: group_1.id, - allow: false, - } - .save(&pool) - .await - .unwrap(); + AclRuleGroup::new(rule.id, group_1.id, false) + .save(&pool) + .await + .unwrap(); // Get rule info let mut conn = pool.acquire().await.unwrap(); diff --git a/crates/defguard_core/src/enterprise/firewall/tests.rs b/crates/defguard_core/src/enterprise/firewall/tests.rs index 2934ef4921..3f0d480b67 100644 --- a/crates/defguard_core/src/enterprise/firewall/tests.rs +++ b/crates/defguard_core/src/enterprise/firewall/tests.rs @@ -824,99 +824,79 @@ async fn create_acl_rule( // create related objects // locations for location_id in locations { - let obj = AclRuleNetwork { - id: NoId, - rule_id, - network_id: location_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleNetwork::new(rule_id, location_id) + .save(&mut *conn) + .await + .unwrap(); } // allowed users for user_id in allowed_users { - let obj = AclRuleUser { - id: NoId, - allow: true, - rule_id, - user_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleUser::new(rule_id, user_id, true) + .save(&mut *conn) + .await + .unwrap(); } // denied users for user_id in denied_users { - let obj = AclRuleUser { - id: NoId, - allow: false, - rule_id, - user_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleUser::new(rule_id, user_id, false) + .save(&mut *conn) + .await + .unwrap(); } // allowed groups for group_id in allowed_groups { - let obj = AclRuleGroup { - id: NoId, - allow: true, - rule_id, - group_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleGroup::new(rule_id, group_id, true) + .save(&mut *conn) + .await + .unwrap(); } // denied groups for group_id in denied_groups { - let obj = AclRuleGroup { - id: NoId, - allow: false, - rule_id, - group_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleGroup::new(rule_id, group_id, false) + .save(&mut *conn) + .await + .unwrap(); } // allowed devices for device_id in allowed_network_devices { - let obj = AclRuleDevice { - id: NoId, - allow: true, - rule_id, - device_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleDevice::new(rule_id, device_id, true) + .save(&mut *conn) + .await + .unwrap(); } // denied devices for device_id in denied_network_devices { - let obj = AclRuleDevice { - id: NoId, - allow: false, - rule_id, - device_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleDevice::new(rule_id, device_id, false) + .save(&mut *conn) + .await + .unwrap(); } // destination ranges for range in destination_ranges { - let obj = AclRuleDestinationRange { + AclRuleDestinationRange { id: NoId, rule_id, start: range.0, end: range.1, - }; - obj.save(&mut *conn).await.unwrap(); + } + .save(&mut *conn) + .await + .unwrap(); } // aliases for alias_id in aliases { - let obj = AclRuleAlias { - id: NoId, - rule_id, - alias_id, - }; - obj.save(&mut *conn).await.unwrap(); + AclRuleAlias::new(rule_id, alias_id) + .save(&mut *conn) + .await + .unwrap(); } // convert to output format @@ -2479,12 +2459,10 @@ async fn test_expired_acl_rules_ipv4(_: PgPoolOptions, options: PgConnectOptions // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2548,12 +2526,10 @@ async fn test_expired_acl_rules_ipv6(_: PgPoolOptions, options: PgConnectOptions // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2620,12 +2596,10 @@ async fn test_expired_acl_rules_ipv4_and_ipv6(_: PgPoolOptions, options: PgConne // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2688,12 +2662,10 @@ async fn test_disabled_acl_rules_ipv4(_: PgPoolOptions, options: PgConnectOption // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2757,12 +2729,10 @@ async fn test_disabled_acl_rules_ipv6(_: PgPoolOptions, options: PgConnectOption // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2829,12 +2799,10 @@ async fn test_disabled_acl_rules_ipv4_and_ipv6(_: PgPoolOptions, options: PgConn // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2897,12 +2865,10 @@ async fn test_unapplied_acl_rules_ipv4(_: PgPoolOptions, options: PgConnectOptio // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -2966,12 +2932,10 @@ async fn test_unapplied_acl_rules_ipv6(_: PgPoolOptions, options: PgConnectOptio // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -3038,12 +3002,10 @@ async fn test_unapplied_acl_rules_ipv4_and_ipv6(_: PgPoolOptions, options: PgCon // assign rules to location for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -3184,20 +3146,16 @@ async fn test_acl_rules_all_locations_ipv4(_: PgPoolOptions, options: PgConnectO // assign rules to locations for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_1.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_1.id) + .save(&pool) + .await + .unwrap(); } for rule in [&acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_2.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_2.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -3344,20 +3302,16 @@ async fn test_acl_rules_all_locations_ipv6(_: PgPoolOptions, options: PgConnectO // assign rules to locations for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_1.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_1.id) + .save(&pool) + .await + .unwrap(); } for rule in [&acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_2.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_2.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -3518,20 +3472,16 @@ async fn test_acl_rules_all_locations_ipv4_and_ipv6(_: PgPoolOptions, options: P // assign rules to locations for rule in [&acl_rule_1, &acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_1.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_1.id) + .save(&pool) + .await + .unwrap(); } for rule in [&acl_rule_2] { - let obj = AclRuleNetwork { - id: NoId, - rule_id: rule.id, - network_id: location_2.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(rule.id, location_2.id) + .save(&pool) + .await + .unwrap(); } let mut conn = pool.acquire().await.unwrap(); @@ -3645,21 +3595,17 @@ async fn test_alias_kinds(_: PgPoolOptions, options: PgConnectOptions) { .await .unwrap(); for alias in [&destination_alias, &component_alias] { - let obj = AclRuleAlias { - id: NoId, - rule_id: acl_rule.id, - alias_id: alias.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleAlias::new(acl_rule.id, alias.id) + .save(&pool) + .await + .unwrap(); } // assign rule to location - let obj = AclRuleNetwork { - id: NoId, - rule_id: acl_rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(acl_rule.id, location.id) + .save(&pool) + .await + .unwrap(); let mut conn = pool.acquire().await.unwrap(); let generated_firewall_rules = try_get_location_firewall_config(&location, &mut conn) @@ -3840,21 +3786,17 @@ async fn test_destination_alias_only_acl(_: PgPoolOptions, options: PgConnectOpt .await .unwrap(); for alias in [&destination_alias_1, &destination_alias_2] { - let obj = AclRuleAlias { - id: NoId, - rule_id: acl_rule.id, - alias_id: alias.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleAlias::new(acl_rule.id, alias.id) + .save(&pool) + .await + .unwrap(); } // assign rule to location - let obj = AclRuleNetwork { - id: NoId, - rule_id: acl_rule.id, - network_id: location.id, - }; - obj.save(&pool).await.unwrap(); + AclRuleNetwork::new(acl_rule.id, location.id) + .save(&pool) + .await + .unwrap(); let mut conn = pool.acquire().await.unwrap(); let generated_firewall_rules = try_get_location_firewall_config(&location, &mut conn) diff --git a/crates/defguard_core/src/grpc/gateway/handler.rs b/crates/defguard_core/src/grpc/gateway/handler.rs index 0e0219a3d1..2e14b272fa 100644 --- a/crates/defguard_core/src/grpc/gateway/handler.rs +++ b/crates/defguard_core/src/grpc/gateway/handler.rs @@ -413,8 +413,9 @@ impl GatewayHandler { ) { None => { warn!( - "Failed to parse peer stats update. Skipping sending message to session manager." - ) + "Failed to parse peer stats update. Skipping sending \ + message to session manager." + ); } Some(message) => { if let Err(err) = self.peer_stats_tx.send(message) {