use zeph_core::channel::ChannelError;
#[must_use]
pub fn all_lists_empty(lists: &[&[String]]) -> bool {
lists.iter().all(|list| list.is_empty())
}
pub fn require_configured_allowlist(
channel: &str,
lists: &[&[String]],
) -> Result<(), ChannelError> {
if all_lists_empty(lists) {
tracing::error!("{channel}: allowlist is empty; refusing to start an open channel");
return Err(ChannelError::Other(format!(
"{channel} allowlist must not be empty"
)));
}
Ok(())
}
#[must_use]
pub fn is_identity_allowed(identity: Option<&str>, allowed: &[String]) -> bool {
allowed.is_empty() || identity.is_some_and(|id| allowed.iter().any(|a| a == id))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_lists_empty_true_when_all_empty() {
let a: Vec<String> = vec![];
let b: Vec<String> = vec![];
assert!(all_lists_empty(&[&a, &b]));
}
#[test]
fn all_lists_empty_false_when_any_non_empty() {
let a: Vec<String> = vec![];
let b = vec!["x".to_string()];
assert!(!all_lists_empty(&[&a, &b]));
}
#[test]
fn require_configured_allowlist_errs_when_all_empty() {
let a: Vec<String> = vec![];
let b: Vec<String> = vec![];
let result = require_configured_allowlist("test", &[&a, &b]);
assert!(matches!(result, Err(ChannelError::Other(_))));
}
#[test]
fn require_configured_allowlist_ok_when_one_list_configured() {
let a: Vec<String> = vec![];
let b = vec!["user1".to_string()];
let result = require_configured_allowlist("test", &[&a, &b]);
assert!(result.is_ok());
}
#[test]
fn is_identity_allowed_permits_all_when_empty() {
assert!(is_identity_allowed(None, &[]));
assert!(is_identity_allowed(Some("anyone"), &[]));
}
#[test]
fn is_identity_allowed_known_identity_is_permitted() {
let allowed = vec!["alice".to_string(), "bob".to_string()];
assert!(is_identity_allowed(Some("alice"), &allowed));
assert!(is_identity_allowed(Some("bob"), &allowed));
}
#[test]
fn is_identity_allowed_unknown_identity_is_rejected() {
let allowed = vec!["alice".to_string()];
assert!(!is_identity_allowed(Some("eve"), &allowed));
assert!(!is_identity_allowed(None, &allowed));
}
}