From 2e8f9e8043594c8e8ce57daabe4a26a8fb7e9826 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Sat, 25 Mar 2023 21:44:51 +0200 Subject: Insist that git command paths are relative --- readme.org | 4 ++-- src/git.rs | 5 ++--- src/parser.rs | 44 +++++++++++++++++++++++++++++++++++++------- tests/server_shell.rs | 6 +++--- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/readme.org b/readme.org index 6d1e388..1153c29 100644 --- a/readme.org +++ b/readme.org @@ -27,8 +27,8 @@ Pijul. - [X] history (only within same session) - [X] don't quit interactive shell sessions if there's an error - [X] help command -- [ ] restrict repos to only acceptable paths - - [ ] clone / pull +- [-] restrict repos to only acceptable paths + - [X] clone / pull - [ ] push - [ ] git init of shared repos - [ ] listing of repos diff --git a/src/git.rs b/src/git.rs index 877e336..f7dbe13 100644 --- a/src/git.rs +++ b/src/git.rs @@ -19,9 +19,8 @@ fn personal_git_dir() -> Result { } fn is_valid_personal_git_repo(path: &PathBuf) -> Result { - let valid_dir = personal_git_dir()?.canonicalize()?; - let canonical_path = path.canonicalize()?; - let relative_path = match canonical_path.strip_prefix(&valid_dir) { + let valid_dir = personal_git_dir()?; + let relative_path = match path.strip_prefix(&valid_dir) { Ok(relative_path) => relative_path, Err(_) => { return Ok(false); diff --git a/src/parser.rs b/src/parser.rs index 6a6459b..55a2be9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,8 @@ -use clap::{Parser, Subcommand}; -use std::{path::PathBuf, str::FromStr}; +use clap::Parser; +use std::{ + path::{Path, PathBuf}, + str::FromStr, +}; use thiserror::Error; #[derive(Parser, Clone, Debug, PartialEq, Eq)] @@ -13,11 +16,6 @@ pub enum ShackleCommand { GitReceivePack(GitReceivePackArgs), } -#[derive(Subcommand, Clone, Debug, PartialEq, Eq)] -pub enum GitCommand { - UploadPack(GitUploadPackArgs), -} - #[derive(Parser, Clone, Debug, PartialEq, Eq)] pub struct GitInitArgs { pub repo_name: String, @@ -35,6 +33,7 @@ pub struct GitUploadPackArgs { pub stateless_rpc: bool, #[arg(long)] pub advertise_refs: bool, + #[arg(value_parser = RelativePathParser)] pub directory: PathBuf, } @@ -42,6 +41,7 @@ pub struct GitUploadPackArgs { pub struct GitReceivePackArgs { #[arg(long)] pub http_backend_info_refs: bool, + #[arg(value_parser = RelativePathParser)] pub directory: PathBuf, } @@ -74,6 +74,36 @@ impl FromStr for ShackleCommand { } } +#[derive(Clone)] +struct RelativePathParser; + +impl clap::builder::TypedValueParser for RelativePathParser { + type Value = std::path::PathBuf; + + fn parse_ref( + &self, + cmd: &clap::Command, + arg: Option<&clap::Arg>, + value: &std::ffi::OsStr, + ) -> Result { + clap::builder::TypedValueParser::parse(self, cmd, arg, value.to_owned()) + } + + fn parse( + &self, + cmd: &clap::Command, + arg: Option<&clap::Arg>, + value: std::ffi::OsString, + ) -> Result { + let raw = clap::builder::PathBufValueParser::default().parse(cmd, arg, value)?; + Ok(raw + .strip_prefix(Path::new("/~")) + .or_else(|_| raw.strip_prefix(Path::new("~"))) + .map(|m| m.to_owned()) + .unwrap_or(raw)) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/tests/server_shell.rs b/tests/server_shell.rs index ea01791..721716b 100644 --- a/tests/server_shell.rs +++ b/tests/server_shell.rs @@ -166,7 +166,7 @@ fn clone_git_repo(c: &TestContext, path: &str) -> Assert { } fn clone_git_repo_relative_path(c: &TestContext, repo_name: &str) -> Assert { - clone_git_repo(c, &format!("/home/shukkie/git/shukkie/{}.git", repo_name)) + clone_git_repo(c, &format!("/~/git/shukkie/{}.git", repo_name)) } #[test] @@ -217,7 +217,7 @@ fn git_push_works() -> Result<()> { #[test] fn git_clone_can_not_target_repo_outside_allowed_paths() -> Result<()> { let c = spawn_ssh_server()?; - clone_git_repo(&c, "/home/shukkie/disallowed.git") + clone_git_repo(&c, "/~/disallowed.git") .failure() .stderr(predicates::str::contains("Path is not accessible")); @@ -227,7 +227,7 @@ fn git_clone_can_not_target_repo_outside_allowed_paths() -> Result<()> { #[test] fn git_clone_can_not_target_repo_outside_allowed_paths_where_path_doesnt_exist() -> Result<()> { let c = spawn_ssh_server()?; - clone_git_repo(&c, "/home/shukkie/disallowed-doesnt-exist.git") + clone_git_repo(&c, "/~/disallowed-doesnt-exist.git") .failure() .stderr(predicates::str::contains("Path is not accessible")); -- cgit v1.2.3