diff options
-rw-r--r-- | readme.org | 8 | ||||
-rw-r--r-- | src/git.rs | 38 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | tests/server_shell.rs | 1 |
4 files changed, 41 insertions, 8 deletions
@@ -13,6 +13,8 @@ Pijul. * Roadmap +** MVP + - [X] interactive command prompt - [X] non-interactive commands can be run with -c - [X] exit command @@ -32,8 +34,12 @@ Pijul. - [ ] listing of repos - [ ] set repo descriptions - [ ] set the main branch of a repo -- [ ] git archive with git upload-archive - [ ] help docs on all the commands + +** Post-MVP + +- [ ] git archive with git upload-archive +- [ ] git config management around protected branches - [ ] move a repo to a different group - [ ] housekeeping git tasks (git fsck, git gc) - [ ] pijul fetch and pijul push @@ -3,19 +3,42 @@ use crate::{ ShackleError, }; use git2::{Repository, RepositoryInitOptions}; -use std::{path::PathBuf, process::Command}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; use user_info::get_username; pub struct GitInitResult { pub path: PathBuf, } -pub fn init(repo_name: &str) -> Result<GitInitResult, ShackleError> { +fn personal_git_dir() -> Result<PathBuf, ShackleError> { let username = get_username().ok_or(ShackleError::UserReadError)?; - let mut path = PathBuf::from("git"); - path.push(username); - path.push(repo_name); - path.set_extension("git"); + Ok(Path::new("git").join(username)) +} + +fn is_valid_personal_git_repo(path: &PathBuf) -> Result<bool, ShackleError> { + let valid_dir = personal_git_dir()?.canonicalize()?; + let canonical_path = path.canonicalize()?; + let relative_path = match canonical_path.strip_prefix(&valid_dir) { + Ok(relative_path) => relative_path, + Err(_) => { + return Ok(false); + } + }; + + if relative_path.parent() != Some(Path::new("")) + || relative_path.extension().map(|ext| ext == "git") != Some(true) + { + return Ok(false); + } + + Ok(true) +} + +pub fn init(repo_name: &str) -> Result<GitInitResult, ShackleError> { + let path = personal_git_dir()?.join(repo_name).with_extension("git"); Repository::init_opts( &path, @@ -29,6 +52,9 @@ pub fn init(repo_name: &str) -> Result<GitInitResult, ShackleError> { pub fn upload_pack(upload_pack_args: &GitUploadPackArgs) -> Result<(), ShackleError> { let mut command = Command::new("git-upload-pack"); + if !is_valid_personal_git_repo(&upload_pack_args.directory)? { + return Err(ShackleError::InvalidDirectory); + } if upload_pack_args.strict { command.arg("strict"); @@ -39,4 +39,6 @@ pub enum ShackleError { ReadlineError(#[from] ReadlineError), #[error("Could not get the current user name")] UserReadError, + #[error("Path is not accessible")] + InvalidDirectory, } diff --git a/tests/server_shell.rs b/tests/server_shell.rs index 72329d3..756c5a8 100644 --- a/tests/server_shell.rs +++ b/tests/server_shell.rs @@ -215,7 +215,6 @@ fn git_push_works() -> Result<()> { } #[test] -#[ignore = "Need to put the repo in the right dir first"] fn git_clone_can_not_target_repo_outside_allowed_paths() -> Result<()> { let c = spawn_ssh_server()?; clone_git_repo(&c, "/home/shukkie/disallowed.git") |