minio-rsc 0.1.3

rust for minio
Documentation
#![allow(unused)]
use crypto::digest::Digest;
use crypto::md5::Md5;
use once_cell::sync::Lazy;
use regex::Regex;

use crate::errors::ValueError;

pub static EMPTY_CONTENT_SHA256: &str =
    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

static _VALID_IP_ADDRESS: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\d+\.){3}\d+$").unwrap());

static _VALID_NAME: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$").unwrap());

static _IS_URLENCODE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^([0-9a-zA-Z-.~_]|(%[0-9A-F]{2}))*$").unwrap());

static _VALIE_UUID: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}*$")
        .unwrap()
});

/// Check whether bucket name is valid
pub fn check_bucket_name(name: &str) -> Result<bool, ValueError> {
    if name.len() < 3 || name.len() > 63 {
        Err(ValueError::from(
            "Bucket name must be between 3 (min) and 63 (max) characters long.",
        ))?;
    };
    if !_VALID_NAME.is_match(name) {
        Err(ValueError::from(
            "Bucket name can consist only of lowercase letters, numbers, dots (.), and hyphens (-). must begin and end with a letter or number.",
        ))?;
    }
    if name.find("..").is_some() || name.find(".-").is_some() || name.find("-.").is_some() {
        Err(ValueError::from(
            "Bucket name cannot contain two adjacent periods, or a period adjacent to a hyphen.",
        ))?;
    };
    if name.starts_with("xn--") {
        Err(ValueError::from(
            "Bucket name cannot start with the prefix xn--.",
        ))?;
    }
    if name.ends_with("-s3alias") {
        Err(ValueError::from(
            "Bucket name cannot end with the suffix -s3alias.",
        ))?;
    }
    if _VALID_IP_ADDRESS.is_match(name) {
        Err(ValueError::from("Bucket name cannot be an ip address"))?;
    };
    return Ok(true);
}

/// Compute MD5 of data and return hash as Base64 encoded value.
pub fn md5sum_hash(date: &[u8]) -> String {
    let mut hasher = Md5::new();
    hasher.input(date);
    let mut result: [u8; 16] = [0; 16];
    hasher.result(&mut result);
    base64::encode(result)
}

/// uri encode every byte except the unreserved characters: 'A'-'Z', 'a'-'z', '0'-'9', '-', '.', '_', and '~'.
#[inline]
pub fn urlencode(data: &str, safe_slash: bool) -> String {
    urlencode_binary(data.as_bytes(), safe_slash)
}

pub fn urlencode_binary(data: &[u8], safe_slash: bool) -> String {
    let s = urlencoding::encode_binary(data).into_owned();
    if safe_slash {
        s.replace("%2F", "/")
    } else {
        s
    }
}

/// check text is uuid foramt
pub fn is_uuid(text: &str) -> bool {
    text.len() == 36 && _VALIE_UUID.is_match(text)
}

/// check text is be url encode
pub fn is_urlencoded(text: &str) -> bool {
    _IS_URLENCODE.is_match(text)
}

#[cfg(test)]
mod tests {
    use crate::utils::is_urlencoded;

    use super::check_bucket_name;
    #[test]
    fn test_check_bucket_name() {
        assert!(check_bucket_name("test").is_ok());
        assert!(check_bucket_name("Test").is_err());
        assert!(check_bucket_name("test..t").is_err());
        assert!(check_bucket_name("test-.d").is_err());
        assert!(check_bucket_name("xn--test").is_err());
        assert!(check_bucket_name("test-s3alias").is_err());
        assert!(check_bucket_name("127.0.0.1").is_err());
        assert!(is_urlencoded("uri-encode_.~%AA%20"));
        assert!(!is_urlencoded("uri encode"));
        assert!(!is_urlencoded("uri%2aencode"));
        assert!(!is_urlencoded("uri%2Gencode"));
    }
}