dip/examples/github.rs

113 lines
2.9 KiB
Rust
Raw Normal View History

2018-08-16 01:31:15 +00:00
extern crate dip;
2018-08-16 01:44:53 +00:00
extern crate hmac;
2018-08-16 01:31:15 +00:00
extern crate secstr;
extern crate serde_json;
extern crate sha1;
#[macro_use]
extern crate serde_derive;
extern crate failure;
2018-08-16 01:44:53 +00:00
extern crate generic_array;
2018-08-16 01:31:15 +00:00
#[macro_use]
extern crate structopt;
use std::collections::HashMap;
use std::env;
2018-08-16 01:44:53 +00:00
use std::io::{self, Read};
use std::iter::FromIterator;
use std::path::PathBuf;
use std::process::Command;
2018-08-16 01:31:15 +00:00
2018-08-16 01:44:53 +00:00
use failure::{err_msg, Error};
use generic_array::GenericArray;
use hmac::{Hmac, Mac};
2018-08-16 01:31:15 +00:00
use secstr::*;
use sha1::Sha1;
use structopt::StructOpt;
#[derive(StructOpt)]
struct Opt {
/// JSON input
#[structopt(short = "c", long = "config")]
pub config: String,
}
2018-08-16 15:18:45 +00:00
#[derive(Debug, Serialize, Deserialize)]
2018-08-16 01:31:15 +00:00
struct Config {
secret: String,
#[serde(default)]
2018-08-16 15:18:45 +00:00
disable_hmac_verify: bool,
2018-08-16 21:06:23 +00:00
#[serde(default = "default_path")]
path: PathBuf,
2018-08-16 01:31:15 +00:00
}
#[derive(Serialize, Deserialize)]
struct Payload {
body: String,
headers: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize)]
struct RepositoryInfo {
clone_url: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct GithubPayload {
repository: RepositoryInfo,
}
2018-08-16 21:06:23 +00:00
fn default_path() -> PathBuf {
PathBuf::from(".")
}
2018-08-21 01:53:37 +00:00
fn main() {
2018-08-16 01:31:15 +00:00
let args = Opt::from_args();
2018-08-21 01:53:37 +00:00
let config: Config = serde_json::from_str(&args.config).expect("Could not parse config.");
2018-08-16 15:18:45 +00:00
println!("{:?}", config);
2018-08-16 01:31:15 +00:00
let mut payload = String::new();
2018-08-21 01:53:37 +00:00
io::stdin()
.read_to_string(&mut payload)
.expect("Could not read from stdin");
let payload: Payload = serde_json::from_str(&payload)
.expect(&format!("Could not parse stdin into json: '{}'", payload));
2018-08-16 01:31:15 +00:00
2018-08-16 15:18:45 +00:00
if !config.disable_hmac_verify {
let secret = GenericArray::from_iter(config.secret.bytes());
let mut mac = Hmac::<Sha1>::new(&secret);
mac.input(payload.body.as_bytes());
2018-08-21 01:53:37 +00:00
let signature = mac
.result()
2018-08-16 15:18:45 +00:00
.code()
.into_iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<_>>()
.join("");
2018-08-16 01:44:53 +00:00
2018-08-16 15:18:45 +00:00
let auth = payload
.headers
.get("x-hub-signature")
2018-08-21 01:53:37 +00:00
.ok_or(err_msg("Missing auth header"))
.expect("Missing auth header");
2018-08-16 01:31:15 +00:00
2018-08-16 15:18:45 +00:00
let left = SecStr::from(format!("sha1={}", signature));
let right = SecStr::from(auth.bytes().collect::<Vec<_>>());
assert!(left == right, "HMAC signature didn't match",);
2018-08-16 15:18:45 +00:00
}
2018-08-16 01:31:15 +00:00
2018-08-21 01:53:37 +00:00
let payload: GithubPayload =
serde_json::from_str(&payload.body).expect("Could not parse Github input into json");
let mut target_path =
PathBuf::from(env::var("DIP_WORKDIR").expect("Could not determine working directory"));
2018-08-16 21:06:23 +00:00
target_path.push(&config.path);
Command::new("git")
.arg("clone")
.arg(&payload.repository.clone_url)
.arg("--recursive")
.arg("--depth")
.arg("1")
.arg(&target_path)
2018-08-21 01:53:37 +00:00
.output()
.expect("Could not spawn process to clone");
2018-08-16 01:31:15 +00:00
}