Skip to content

Commit

Permalink
adds git clone (#113)
Browse files Browse the repository at this point in the history
* adds git clone
  • Loading branch information
Jerboa-app committed May 29, 2024
1 parent fe61315 commit b6743b7
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ quick-xml = "0.31.0"
indicatif = "0.17.8"
uuid = { version = "1.8.0", features = ["v4", "fast-rng", "macro-diagnostics"]}
cron = "0.12.1"
git2 = "0.18.3"

[profile.dev]
opt-level = 0
Expand Down
38 changes: 35 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,47 @@ impl ContentConfig
}
}

/// Passphrase or ssh authentication setup (plaintext storage)
/// - ```key_path```: optional location of ssh key (ssh connection will be used)
/// - ```user```: user name for authentication
/// - ```passphrase```: passphrase for ssh key or for user-pass auth
#[derive(Clone, Serialize, Deserialize)]
pub struct GitAuthConfig
{
pub key_path: Option<String>,
pub user: String,
pub passphrase: String
}

/// Git repository busser will track for content
/// - ```remote```: the url (public or private)
/// - ```branch```: the tracked branch
/// - ```auth```: if present either ssh key or passphrase will be used
#[derive(Clone, Serialize, Deserialize)]
pub struct GitConfig
{
pub remote: String,
pub branch: String,
pub auth: Option<GitAuthConfig>
}

/// Configure the server
/// - ```port_https```: https port to serve on
/// - ```port_http```: http port to serve on
/// - ```notification_endpoint```: currently unspported Discord webhook
/// - ```cert_path```: ssl certificate
/// - ```key_path```: ssl key
/// - ```domain```: domain name for https redirect etc.
/// - ```api_token```: token to use for the server's POST api
/// - ```throttle```: [ThrottleConfig]
/// - ```stats```: [StatsConfig]
/// - ```content```: [ContentConfig]
/// - ```api_token```: token to use for the server's POST api
/// - ```git```: [GitConfig] if present busser will track a git repo for content
///
/// <div class="warning"><p>The config.json is a sensitive file which may contain plaintext access tokens/ passphrases.
/// Content matching "config.json" is not served.
/// </p>
/// </div>
#[derive(Clone, Serialize, Deserialize)]
pub struct Config
{
Expand All @@ -132,10 +162,11 @@ pub struct Config
pub cert_path: String,
pub key_path: String,
pub domain: String,
pub api_token: Option<String>,
pub throttle: ThrottleConfig,
pub stats: StatsConfig,
pub content: ContentConfig,
pub api_token: Option<String>
pub git: Option<GitConfig>
}

impl Config
Expand All @@ -150,10 +181,11 @@ impl Config
cert_path: "certs/cert.pem".to_string(),
key_path: "certs/key.pem".to_string(),
domain: "127.0.0.1".to_string(),
api_token: None,
throttle: ThrottleConfig::default(),
stats: StatsConfig::default(),
content: ContentConfig::default(),
api_token: None
git: None
}
}

Expand Down
1 change: 1 addition & 0 deletions src/content/sitemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ impl SiteMap

for content in contents
{
if content.get_uri().contains("config.json") { continue }
crate::debug(format!("Adding content {:?}", content.preview(64)), None);
let path = config.content.path.clone()+"/";
let uri = parse_uri(content.get_uri(), path);
Expand Down
70 changes: 70 additions & 0 deletions src/integrations/git/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::path::Path;

use git2::{Cred, RemoteCallbacks, Repository};

use crate::config::GitConfig;

/// Attempt to clone a remote repo from a [crate::config::GitConfig]
pub fn from_clone(path: String, config: &GitConfig) -> Result<Repository, git2::Error>
{
if let GitConfig{auth: Some(_), remote: _, branch: _} = config
{
let auth = config.auth.clone().unwrap();
let result = match &auth.key_path
{
Some(_) =>
{
let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(|_url, _username_from_url, _allowed_types|
{
Cred::ssh_key(
&auth.user,
None,
Path::new(&auth.key_path.clone().unwrap()),
Some(&auth.passphrase),
)
});
callbacks
},
None =>
{
let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(|_url, _username_from_url, _allowed_types|
{
Cred::userpass_plaintext(
&auth.user,
&auth.passphrase,
)
});
callbacks
}
};

let mut fo = git2::FetchOptions::new();
fo.remote_callbacks(result);
let mut builder = git2::build::RepoBuilder::new();
builder.fetch_options(fo);
builder.branch(&config.branch);
match builder.clone(&config.remote,Path::new(&path))
{
Ok(repo) => Ok(repo),
Err(e) =>
{
crate::debug(format!("Error {} while cloning (authenticated) repo at {}", e, config.remote), None);
Err(e)
}
}
}
else
{
match Repository::clone(&config.remote, path)
{
Ok(repo) => Ok(repo),
Err(e) =>
{
crate::debug(format!("Error {} while cloning (pub) repo at {}", e, config.remote), None);
Err(e)
}
}
}
}
1 change: 1 addition & 0 deletions src/integrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use regex::Regex;
use crate::util::{read_bytes, dump_bytes};

pub mod discord;
pub mod git;
pub mod webhook;

/// Uses openssl to verify the request body via the given hmac_token
Expand Down
2 changes: 2 additions & 0 deletions tests/test_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ mod config
assert_eq!(config.key_path, "certs/key.pem");
assert_eq!(config.domain, "127.0.0.1");

assert!(config.git.is_none());

}

#[test]
Expand Down
84 changes: 84 additions & 0 deletions tests/test_git.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
mod common;

#[cfg(test)]
mod git
{
use std::{fs::remove_dir_all, path::Path};

use busser::{config::{GitAuthConfig, GitConfig}, integrations::git::from_clone};

#[test]
pub fn test_clone()
{
let config = GitConfig
{
remote: "https://github.com/JerboaBurrow/Busser".into(),
branch: "main".into(),
auth: None,
};

let path = "tests/test_clone";
let repo = from_clone(path.into(), &config);

assert!(repo.is_ok());
assert!(!repo.as_ref().unwrap().is_empty().unwrap());
assert!(Path::exists(Path::new(path)));

if Path::exists(Path::new(path))
{
let _ = remove_dir_all(Path::new(path));
}
}

#[test]
pub fn test_key_authed_clone()
{
let config = GitConfig
{
remote: "https://github.com/JerboaBurrow/test".into(),
branch: "main".into(),
auth: Some(GitAuthConfig
{
key_path: Some("not_a_key".into()),
user: "not_a_user".into(),
passphrase: "not_a_passphrase".into(),
}),
};

let path = "tests/test_key_authed_clone";
let repo = from_clone(path.into(), &config);

assert!(repo.is_err());

if Path::exists(Path::new(path))
{
let _ = remove_dir_all(Path::new(path));
}
}

#[test]
pub fn test_pass_authed_clone()
{
let config = GitConfig
{
remote: "https://github.com/JerboaBurrow/test".into(),
branch: "main".into(),
auth: Some(GitAuthConfig
{
key_path: None,
user: "not_a_user".into(),
passphrase: "not_a_passphrase".into(),
}),
};

let path = "tests/test_pass_authed_clone";
let repo = from_clone(path.into(), &config);

assert!(repo.is_err());

if Path::exists(Path::new(path))
{
let _ = remove_dir_all(Path::new(path));
}
}
}

0 comments on commit b6743b7

Please sign in to comment.