From: Scott Worley Date: Fri, 18 Nov 2022 21:09:21 +0000 (-0800) Subject: Path validation X-Git-Tag: v0.2.0~18 X-Git-Url: http://git.scottworley.com/voter/commitdiff_plain/c8402f1cb2962db5a2036c9273f62fff4c8c100c?ds=sidebyside Path validation --- diff --git a/src/main.rs b/src/main.rs index 574d43f..15a1655 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,51 @@ -fn respond(request: cgi::Request) -> Result { - let greeting = std::fs::read_to_string("greeting.txt").map_err(|_| "Couldn't open file")?; +use std::path::{Path, PathBuf}; - Ok(cgi::text_response(200, greeting)) +const DATA_PATH: &str = "/var/lib/voter"; + +fn validate_path(path: &str) -> Result { + let invalid_path = || cgi::text_response(404, "Invalid path"); + if path == "/" { + return Err(cgi::text_response(404, "(This is the voting place. You should have been given a more specific URL for the specific thing you've been invited to vote on.)")); + } + if path.contains("..") || !path.starts_with("/") { + return Err(invalid_path()); + } + let dir = Path::new(&format!("{DATA_PATH}{path}")).to_path_buf(); + if !dir + .canonicalize() + .map_err(|_| invalid_path())? + .starts_with(DATA_PATH) + { + return Err(invalid_path()); + } + if !dir.is_dir() { + return Err(invalid_path()); + } + Ok(dir) +} + +fn prompt_for_vote(dir: PathBuf, request: cgi::Request) -> Result { + Err(cgi::text_response(503, "Not Implemented")) +} + +fn record_vote(dir: PathBuf, request: cgi::Request) -> Result { + Err(cgi::text_response(503, "Not Implemented")) +} + +fn respond(request: cgi::Request) -> Result { + let dir = validate_path(request.uri().path())?; + match request.method() { + &cgi::http::Method::GET => prompt_for_vote(dir, request), + &cgi::http::Method::POST => record_vote(dir, request), + _ => Err(cgi::text_response(405, "Huh?")), + } +} + +fn respond_or_report_error(request: cgi::Request) -> cgi::Response { + match respond(request) { + Ok(result) => result, + Err(error) => error, + } } -cgi::cgi_try_main! { respond } +cgi::cgi_main! { respond_or_report_error }