mihomo-rs 2.0.0

A Rust SDK and CLI tool for mihomo proxy management with service lifecycle management, configuration handling, and real-time monitoring
Documentation
use super::{ErrorCode, MihomoError, Result};
use std::path::{Component, Path};

fn validate_simple_name(name: &str, kind: &str, allow_plus: bool, code: ErrorCode) -> Result<()> {
    if name.is_empty() {
        return Err(MihomoError::config_with_code(
            code,
            format!("{kind} cannot be empty"),
        ));
    }

    let path = Path::new(name);
    if path.is_absolute()
        || name.contains('/')
        || name.contains('\\')
        || !matches!(path.components().next(), Some(Component::Normal(_)))
        || path.components().count() != 1
    {
        return Err(MihomoError::config_with_code(
            code,
            format!("Invalid {kind} '{name}'"),
        ));
    }

    if !name.chars().all(|c| {
        c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-') || (allow_plus && c == '+')
    }) {
        return Err(MihomoError::config_with_code(
            code,
            format!("Invalid {kind} '{name}'"),
        ));
    }

    Ok(())
}

pub fn validate_profile_name(name: &str) -> Result<()> {
    validate_simple_name(name, "profile name", false, ErrorCode::InvalidProfileName)
}

pub fn validate_version_name(name: &str) -> Result<()> {
    validate_simple_name(name, "version", true, ErrorCode::InvalidVersion)
}

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

    #[test]
    fn profile_name_validation_rules() {
        assert!(validate_profile_name("alpha-1.2_ok").is_ok());
        assert!(validate_profile_name("../evil").is_err());
        assert!(validate_profile_name("a/b").is_err());
        assert!(validate_profile_name("a\\b").is_err());
        assert!(validate_profile_name("bad name").is_err());
    }

    #[test]
    fn version_name_validation_rules() {
        assert!(validate_version_name("v1.2.3-alpha+build.1").is_ok());
        assert!(validate_version_name("../v1").is_err());
        assert!(validate_version_name("a/b").is_err());
        assert!(validate_version_name("a\\b").is_err());
        assert!(validate_version_name("bad version").is_err());
    }
}