]> git.scottworley.com Git - voter/commitdiff
Path validation
authorScott Worley <scottworley@scottworley.com>
Fri, 18 Nov 2022 21:09:21 +0000 (13:09 -0800)
committerScott Worley <scottworley@scottworley.com>
Sat, 19 Nov 2022 03:22:54 +0000 (19:22 -0800)
src/main.rs

index 574d43f7c9605b6ecc49e80e1fbfdde64fd5e191..15a1655de920522e2526191dc6cd47fd9dbf5c3e 100644 (file)
@@ -1,7 +1,51 @@
-fn respond(request: cgi::Request) -> Result<cgi::Response, String> {
-    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<PathBuf, cgi::Response> {
+    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<cgi::Response, cgi::Response> {
+    Err(cgi::text_response(503, "Not Implemented"))
+}
+
+fn record_vote(dir: PathBuf, request: cgi::Request) -> Result<cgi::Response, cgi::Response> {
+    Err(cgi::text_response(503, "Not Implemented"))
+}
+
+fn respond(request: cgi::Request) -> Result<cgi::Response, cgi::Response> {
+    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 }