spiffe-rs 0.1.0

Rust port of spiffe-go with SPIFFE IDs, bundles, SVIDs, Workload API client, federation helpers, and rustls-based SPIFFE TLS utilities.
Documentation
use crate::spiffeid::charset::is_backcompat_path_char;
use crate::spiffeid::{Error, Result};

pub fn format_path(args: std::fmt::Arguments<'_>) -> Result<String> {
    let path = format!("{}", args);
    validate_path(&path)?;
    Ok(path)
}

pub fn join_path_segments(segments: &[&str]) -> Result<String> {
    let mut out = String::new();
    for segment in segments {
        validate_path_segment(segment)?;
        out.push('/');
        out.push_str(segment);
    }
    Ok(out)
}

pub fn validate_path(path: &str) -> Result<()> {
    if path.is_empty() {
        return Ok(());
    }
    if !path.starts_with('/') {
        return Err(Error::NoLeadingSlash);
    }

    let bytes = path.as_bytes();
    let mut segment_start = 0usize;
    for (idx, &c) in bytes.iter().enumerate() {
        if c == b'/' {
            match &path[segment_start..idx] {
                "/" => return Err(Error::EmptySegment),
                "/." | "/.." => return Err(Error::DotSegment),
                _ => {}
            }
            segment_start = idx;
            continue;
        }
        if !is_valid_path_segment_char(c) {
            return Err(Error::BadPathSegmentChar);
        }
    }

    match &path[segment_start..] {
        "/" => Err(Error::TrailingSlash),
        "/." | "/.." => Err(Error::DotSegment),
        _ => Ok(()),
    }
}

pub fn validate_path_segment(segment: &str) -> Result<()> {
    match segment {
        "" => return Err(Error::EmptySegment),
        "." | ".." => return Err(Error::DotSegment),
        _ => {}
    }
    for &c in segment.as_bytes() {
        if !is_valid_path_segment_char(c) {
            return Err(Error::BadPathSegmentChar);
        }
    }
    Ok(())
}

fn is_valid_path_segment_char(c: u8) -> bool {
    matches!(c, b'a'..=b'z')
        || matches!(c, b'A'..=b'Z')
        || matches!(c, b'0'..=b'9')
        || matches!(c, b'-' | b'.' | b'_')
        || is_backcompat_path_char(c)
}