liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! The service certificate key is fetched once, never taken from pass JWKS.

use super::CertificateRefusal;
use std::net::IpAddr;
use std::num::NonZeroUsize;
use std::time::Duration;

#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct ServiceKey {
    ed25519: String,
}

/// Resolves the service-key route including the configured API prefix.
///
/// # Errors
/// A foreign-scheme, credential-bearing or insecure non-loopback API base.
pub fn endpoint(base: &str) -> Result<reqwest::Url, CertificateRefusal> {
    let mut url = reqwest::Url::parse(base).map_err(|_| CertificateRefusal::ServiceKey)?;
    let host = url.host_str().ok_or(CertificateRefusal::ServiceKey)?;
    let loopback = host == "localhost"
        || host
            .trim_matches(['[', ']'])
            .parse::<IpAddr>()
            .is_ok_and(|address| address.is_loopback());
    if !matches!(url.scheme(), "https" | "http")
        || (url.scheme() == "http" && !loopback)
        || !url.username().is_empty()
        || url.password().is_some()
        || url.query().is_some()
        || url.fragment().is_some()
    {
        return Err(CertificateRefusal::ServiceKey);
    }
    if !url.path().ends_with('/') {
        url.set_path(&format!("{}/", url.path()));
    }
    url.join("service-key")
        .map_err(|_| CertificateRefusal::ServiceKey)
}

/// Fetches once with no credential, no redirects and a configured allocation bound.
/// `deadline` bounds this one in-flight request; there is no idle timer or retry.
///
/// # Errors
/// A refused endpoint, transport/status failure, oversized or malformed response,
/// or an invalid Ed25519 service key.
pub fn fetch(
    base: &str,
    bound: NonZeroUsize,
    deadline: Duration,
    handle: &tokio::runtime::Handle,
) -> Result<[u8; 32], CertificateRefusal> {
    if deadline.is_zero() {
        return Err(CertificateRefusal::ServiceKey);
    }
    let endpoint = endpoint(base)?;
    let client = reqwest::Client::builder()
        .redirect(reqwest::redirect::Policy::none())
        .timeout(deadline)
        .build()
        .map_err(|_| CertificateRefusal::ServiceKey)?;
    std::thread::scope(|scope| {
        scope
            .spawn(|| {
                handle.block_on(async {
                    let mut response = client
                        .get(endpoint)
                        .send()
                        .await
                        .map_err(|_| CertificateRefusal::ServiceKey)?;
                    if !response.status().is_success() {
                        return Err(CertificateRefusal::ServiceKey);
                    }
                    let mut bytes = Vec::new();
                    while let Some(chunk) = response
                        .chunk()
                        .await
                        .map_err(|_| CertificateRefusal::ServiceKey)?
                    {
                        if bytes
                            .len()
                            .checked_add(chunk.len())
                            .is_none_or(|length| length > bound.get())
                        {
                            return Err(CertificateRefusal::Bound);
                        }
                        bytes.extend_from_slice(&chunk);
                    }
                    decode(&bytes)
                })
            })
            .join()
    })
    .map_err(|_| CertificateRefusal::ServiceKey)?
}

/// Decodes the unauthenticated route's exact public-key response.
///
/// # Errors
/// Wrong fields, encoding, length, or an invalid/weak Ed25519 service key.
pub fn decode(bytes: &[u8]) -> Result<[u8; 32], CertificateRefusal> {
    let response: ServiceKey =
        serde_json::from_slice(bytes).map_err(|_| CertificateRefusal::ServiceKey)?;
    let mut key = [0; 32];
    hex::decode_to_slice(&response.ed25519, &mut key)
        .map_err(|_| CertificateRefusal::ServiceKey)?;
    let verifying = ed25519_dalek::VerifyingKey::from_bytes(&key)
        .map_err(|_| CertificateRefusal::ServiceKey)?;
    if verifying.is_weak() {
        return Err(CertificateRefusal::ServiceKey);
    }
    Ok(key)
}