notify: ensure that filter/group/endpoint names are unique

Otherwise, a filter with the same name as an already existing
endpoint or group can overwrite it.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Lukas Wagner 2023-07-20 16:31:50 +02:00 committed by Wolfgang Bumiller
parent 62ae1cf959
commit 2756c11c2f
5 changed files with 51 additions and 44 deletions

View File

@ -31,12 +31,7 @@ pub fn get_filter(config: &Config, name: &str) -> Result<FilterConfig, ApiError>
/// Returns an `ApiError` if a filter with the same name already exists or
/// if the filter could not be saved.
pub fn add_filter(config: &mut Config, filter_config: &FilterConfig) -> Result<(), ApiError> {
if get_filter(config, &filter_config.name).is_ok() {
return Err(ApiError::bad_request(
format!("filter '{}' already exists", filter_config.name),
None,
));
}
super::ensure_unique(config, &filter_config.name)?;
config
.config

View File

@ -43,15 +43,7 @@ pub fn add_endpoint(
panic!("name for endpoint config and private config must be identical");
}
if super::endpoint_exists(config, &endpoint_config.name) {
return Err(ApiError::bad_request(
format!(
"endpoint with name '{}' already exists!",
endpoint_config.name
),
None,
));
}
super::ensure_unique(config, &endpoint_config.name)?;
if let Some(filter) = &endpoint_config.filter {
// Check if filter exists

View File

@ -31,12 +31,7 @@ pub fn get_group(config: &Config, name: &str) -> Result<GroupConfig, ApiError> {
/// Returns an `ApiError` if a group with the same name already exists, or
/// if the group could not be saved
pub fn add_group(config: &mut Config, group_config: &GroupConfig) -> Result<(), ApiError> {
if get_group(config, &group_config.name).is_ok() {
return Err(ApiError::bad_request(
format!("group '{}' already exists", group_config.name),
None,
));
}
super::ensure_unique(config, &group_config.name)?;
if group_config.endpoint.is_empty() {
return Err(ApiError::bad_request(
@ -50,7 +45,7 @@ pub fn add_group(config: &mut Config, group_config: &GroupConfig) -> Result<(),
super::filter::get_filter(config, filter)?;
}
check_if_endpoints_exist(config, &group_config.endpoint)?;
super::ensure_endpoints_exist(config, &group_config.endpoint)?;
config
.config
@ -91,7 +86,7 @@ pub fn update_group(
}
if let Some(endpoints) = &updater.endpoint {
check_if_endpoints_exist(config, endpoints)?;
super::ensure_endpoints_exist(config, endpoints)?;
if endpoints.is_empty() {
return Err(ApiError::bad_request(
"group must contain at least one endpoint",
@ -138,19 +133,6 @@ pub fn delete_group(config: &mut Config, name: &str) -> Result<(), ApiError> {
Ok(())
}
fn check_if_endpoints_exist(config: &Config, endpoints: &[String]) -> Result<(), ApiError> {
for endpoint in endpoints {
if !super::endpoint_exists(config, endpoint) {
return Err(ApiError::not_found(
format!("endoint '{endpoint}' does not exist"),
None,
));
}
}
Ok(())
}
// groups cannot be empty, so only build the tests if we have the
// sendmail endpoint available
#[cfg(all(test, feature = "sendmail"))]

View File

@ -87,7 +87,7 @@ fn verify_digest(config: &Config, digest: Option<&[u8]>) -> Result<(), ApiError>
Ok(())
}
fn endpoint_exists(config: &Config, name: &str) -> bool {
fn ensure_endpoint_exists(config: &Config, name: &str) -> Result<(), ApiError> {
let mut exists = false;
#[cfg(feature = "sendmail")]
@ -99,7 +99,33 @@ fn endpoint_exists(config: &Config, name: &str) -> bool {
exists = exists || gotify::get_endpoint(config, name).is_ok();
}
exists
if !exists {
Err(ApiError::not_found(
format!("endpoint '{name}' does not exist"),
None,
))
} else {
Ok(())
}
}
fn ensure_endpoints_exist<T: AsRef<str>>(config: &Config, endpoints: &[T]) -> Result<(), ApiError> {
for endpoint in endpoints {
ensure_endpoint_exists(config, endpoint.as_ref())?;
}
Ok(())
}
fn ensure_unique(config: &Config, entity: &str) -> Result<(), ApiError> {
if config.config.sections.contains_key(entity) {
return Err(ApiError::bad_request(
format!("Cannot create '{entity}', an entity with the same name already exists"),
None,
));
}
Ok(())
}
fn get_referrers(config: &Config, entity: &str) -> Result<HashSet<String>, ApiError> {
@ -324,4 +350,21 @@ mod tests {
assert!(ensure_unused(&config, "sendmail").is_err());
assert!(ensure_unused(&config, "group").is_ok());
}
#[test]
fn test_ensure_unique() {
let config = prepare_config().unwrap();
assert!(ensure_unique(&config, "sendmail").is_err());
assert!(ensure_unique(&config, "group").is_err());
assert!(ensure_unique(&config, "new").is_ok());
}
#[test]
fn test_ensure_endpoints_exist() {
let config = prepare_config().unwrap();
assert!(ensure_endpoints_exist(&config, &vec!["sendmail", "gotify"]).is_ok());
assert!(ensure_endpoints_exist(&config, &vec!["group", "filter"]).is_err());
}
}

View File

@ -33,12 +33,7 @@ pub fn get_endpoint(config: &Config, name: &str) -> Result<SendmailConfig, ApiEr
/// Returns an `ApiError` if an endpoint with the same name already exists,
/// or if the endpoint could not be saved.
pub fn add_endpoint(config: &mut Config, endpoint: &SendmailConfig) -> Result<(), ApiError> {
if super::endpoint_exists(config, &endpoint.name) {
return Err(ApiError::bad_request(
format!("endpoint with name '{}' already exists!", &endpoint.name),
None,
));
}
super::ensure_unique(config, &endpoint.name)?;
if let Some(filter) = &endpoint.filter {
// Check if filter exists