Repository: DioxusLabs/dioxus
File: packages/manganis/manganis-macro/src/asset.rs (Rust)

Code before:

fn resolve_path(raw: &str) -> Result<PathBuf, AssetParseError> {
    if raw.is_empty() {
        return Err(AssetParseError::InvalidPath {
            path: PathBuf::new(),
        });
    }

    // Get the location of the root of the crate which is where all assets are relative to
    //
    // IE
    // /users/dioxus/dev/app/
    // is the root of
    // /users/dioxus/dev/app/assets/blah.css
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
        .map(PathBuf::from)
        .map(std::path::absolute)
        .unwrap()
        .unwrap();

    // 1. the input file should be a pathbuf
    let input = PathBuf::from(raw);

    // 2. absolute path to the asset
    let path =
        std::path::absolute(manifest_dir.join(raw.trim_start_matches('/'))).map_err(|err| {
            AssetParseError::AssetDoesntExist {
                err,
                path: input.clone(),
            }
        })?;

    // 3. Ensure the path is not the current dir or exist outside the current dir
    if path == manifest_dir || !path.starts_with(manifest_dir) || !path.exists() {
        return Err(AssetParseError::InvalidPath { path });
    }

    Ok(path)
}

fn hash_file_contents(file_path: &Path) -> Result<u64, AssetParseError> {
    // Create a hasher
    let mut hash = std::collections::hash_map::DefaultHasher::new();

    // If this is a folder, hash the folder contents
    if file_path.is_dir() {
        let files =
            std::fs::read_dir(file_path).map_err(|err| AssetParseError::AssetDoesntExist {
                err,
                path: file_path.to_path_buf(),
            })?;

Review comment (suggestion):
`std::path::absolute` does not check if the path exists (unlike canonicalize) so this error does not trigger when the path doesn't exist

Code after:

fn resolve_path(raw: &str) -> Result<PathBuf, AssetParseError> {
    // Get the location of the root of the crate which is where all assets are relative to
    //
    // IE
    // /users/dioxus/dev/app/
    // is the root of
    // /users/dioxus/dev/app/assets/blah.css
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
        .map(PathBuf::from)
        .unwrap()
        .canonicalize()
        .unwrap();

    // 1. the input file should be a pathbuf
    let input = PathBuf::from(raw);

    // 2. absolute path to the asset
    let Ok(path) = std::path::absolute(manifest_dir.join(raw.trim_start_matches('/'))) else {
        return Err(AssetParseError::InvalidPath {
            path: input.clone(),
        });
    };

    // 3. Ensure the path exists
    let Ok(path) = path.canonicalize() else {
        return Err(AssetParseError::AssetDoesntExist {
            path: input.clone(),
        });
    };

    // 4. Ensure the path doesn't escape the crate dir
    //
    // - Note: since we called canonicalize on both paths, we can safely compare the parent dirs.
    //   On windows, we can only compare the prefix if both paths are canonicalized (not just absolute)
    //   https://github.com/rust-lang/rust/issues/42869
    if path == manifest_dir || !path.starts_with(manifest_dir) {
        return Err(AssetParseError::InvalidPath { path });
    }

    Ok(path)
}

fn hash_file_contents(file_path: &Path) -> Result<u64, AssetParseError> {
    // Create a hasher
    let mut hash = std::collections::hash_map::DefaultHasher::new();

    // If this is a folder, hash the folder contents
    if file_path.is_dir() {
        let files = std::fs::read_dir(file_path).map_err(|err| AssetParseError::IoError {
            err,