liminal-server 0.27.0

Standalone server for the liminal messaging bus
Documentation
//! ACCESS-012 R2: who a connection on an open exchange says it is.
//!
//! An exchange with no `[auth]` proves nothing about a connection; it can
//! still record what the connection declares, so the services a seat creates
//! carry a name and a list says whose they are. The record is `open:<name>`
//! on the `Connect` frame; any other record, an empty one and a Lys pass
//! record included, is admitted as `open:anonymous`. A gated exchange never
//! reads this: its `Connect` refuses the record as an unknown credential.

/// The prefix of the record an open seat sends and of every holder it is
/// recorded as.
pub const PREFIX: &str = "open:";

/// The name of a connection that declared none.
pub const ANONYMOUS: &str = "anonymous";

/// What an open-access connection declared at `Connect`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeclaredHolder {
    /// `open:<name>`, the name as the record gave it, or anonymous.
    Open(String),
}

impl DeclaredHolder {
    /// Reads the record an open exchange admitted: `open:<name>` with a name
    /// of 1 to 64 of `a-z`, `0-9`, `.`, `_` or `-`; anything else is
    /// anonymous.
    #[must_use]
    pub fn from_record(record: &[u8]) -> Self {
        let name = std::str::from_utf8(record)
            .ok()
            .and_then(|text| text.strip_prefix(PREFIX))
            .filter(|name| is_name(name));
        Self::Open(name.unwrap_or(ANONYMOUS).to_owned())
    }

    /// The holder as every record names it: `open:<name>`.
    #[must_use]
    pub fn record(&self) -> String {
        match self {
            Self::Open(name) => format!("{PREFIX}{name}"),
        }
    }
}

/// Whether `name` is a declared name: 1 to 64 of `a-z`, `0-9`, `.`, `_` or `-`.
#[must_use]
pub fn is_name(name: &str) -> bool {
    (1..=64).contains(&name.len())
        && name.bytes().all(|b| {
            b.is_ascii_lowercase() || b.is_ascii_digit() || matches!(b, b'.' | b'_' | b'-')
        })
}

#[cfg(test)]
mod tests {
    use super::{DeclaredHolder, is_name};

    #[test]
    fn a_record_names_its_holder_or_is_anonymous() {
        assert_eq!(
            DeclaredHolder::from_record(b"open:hermes").record(),
            "open:hermes"
        );
        for record in [
            &b""[..],
            b"open:",
            b"open:Hermes",
            b"hermes",
            b"\xff",
            b"open:a b",
        ] {
            assert_eq!(
                DeclaredHolder::from_record(record).record(),
                "open:anonymous",
                "{record:?}"
            );
        }
    }

    #[test]
    fn a_name_is_one_to_sixty_four_of_the_allowed_bytes() {
        assert!(is_name("hermes") && is_name("a.b_c-d9") && is_name(&"x".repeat(64)));
        assert!(!is_name("") && !is_name("Hermes") && !is_name("a/b") && !is_name(&"x".repeat(65)));
    }
}