summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Wernick <justin@worthe-it.co.za>2023-03-25 21:44:51 +0200
committerJustin Wernick <justin@worthe-it.co.za>2023-03-25 21:46:12 +0200
commit2e8f9e8043594c8e8ce57daabe4a26a8fb7e9826 (patch)
tree2d4931fa07e31c4a6de023e1c6b47398b05cc823
parent9761556033c1faaae37f995ba557c47f9f3c357f (diff)
Insist that git command paths are relative
-rw-r--r--readme.org4
-rw-r--r--src/git.rs5
-rw-r--r--src/parser.rs44
-rw-r--r--tests/server_shell.rs6
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<PathBuf, ShackleError> {
}
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) {
+ 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<Self::Value, clap::Error> {
+ 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<Self::Value, clap::Error> {
+ 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"));