liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
use std::net::SocketAddr;

use crate::config::types::ServerConfig;

/// ACCESS-010 R1: an exchange with no `[auth]` is open mode, and open mode
/// listens on loopback only. Every connection to it is admitted, so the one
/// boundary it has is the machine: `listen_address`, each
/// `extra_listen_addresses` entry and the `[websocket]` listener must name a
/// loopback IP. The health listener is a probe and is not covered. With
/// `[auth]` present nothing here applies.
pub(super) fn validate_open_mode(config: &ServerConfig, errors: &mut Vec<String>) {
    if config.auth.is_some() {
        return;
    }
    refuse_off_loopback("listen_address", config.listen_address, errors);
    for (index, address) in config.extra_listen_addresses.iter().enumerate() {
        refuse_off_loopback(
            &format!("extra_listen_addresses[{index}]"),
            *address,
            errors,
        );
    }
    if let Some(websocket) = config.websocket.as_ref() {
        refuse_off_loopback("websocket.listen_address", websocket.listen_address, errors);
    }
}

fn refuse_off_loopback(field: &str, address: SocketAddr, errors: &mut Vec<String>) {
    if address.ip().is_loopback() {
        return;
    }
    errors.push(format!(
        "open mode (no [auth]): {field} {address} is not loopback; an exchange with no [auth] \
         listens on loopback only, give [auth] to listen elsewhere"
    ));
}