diff --git a/crates/server/src/handlers/assets.rs b/crates/server/src/handlers/assets.rs index d7cf18f..35e7975 100644 --- a/crates/server/src/handlers/assets.rs +++ b/crates/server/src/handlers/assets.rs @@ -1,10 +1,17 @@ -// Copyright 2022 VMware, Inc. +// Copyright 2022-2023 VMware, Inc. // SPDX-License-Identifier: Apache-2.0 use crate::AppData; use actix_files::NamedFile; use actix_web::{web::Data, HttpRequest}; use std::io::{Error, ErrorKind}; +use std::path::{Component, Path}; + +/// Checks if the given component is not normal or absolute. If the component +/// is not valid, it returns true. +fn component_is_valid(component: Component) -> bool { + matches!(component, Component::Normal(_) | Component::RootDir) +} /// Find a static HTML file in the `public` folder. This function is used /// when there's no direct file to be served. It will look for certain patterns @@ -18,19 +25,26 @@ pub async fn handle_assets(req: &HttpRequest) -> Result { .root_path; let uri_path = req.path(); + // Parse the URI as a filesystem path + let parsed_path = Path::new(uri_path); + + // Double-check the given path path does not contain any unexpected value. + // It was previously sanitized, but this is a double check. + if !parsed_path.components().all(component_is_valid) { + return Err(Error::new(ErrorKind::NotFound, "The file is not present")); + } + + let public_folder = root_path.join("public"); + // File path. This is required for the wasm_handler as dynamic routes may capture static files - let file_path = root_path.join(format!("public{uri_path}")); + let file_path = public_folder.join(parsed_path); // A.k.a pretty urls. We may access /about and this matches to /about/index.html - let index_folder_path = root_path.join(format!("public{uri_path}/index.html")); - // Same as before, but the file is located at ./about.html - let html_ext_path = root_path.join(format!("public{uri_path}.html")); + let index_folder_path = public_folder.join(parsed_path).join("index.html"); if file_path.exists() { NamedFile::open_async(file_path).await } else if uri_path.ends_with('/') && index_folder_path.exists() { NamedFile::open_async(index_folder_path).await - } else if !uri_path.ends_with('/') && html_ext_path.exists() { - NamedFile::open_async(html_ext_path).await } else { Err(Error::new(ErrorKind::NotFound, "The file is not present")) }