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;
|
2018-08-16 20:42:28 +00:00
|
|
|
use std::env;
|
2018-08-16 01:44:53 +00:00
|
|
|
use std::io::{self, Read};
|
|
|
|
use std::iter::FromIterator;
|
2018-08-16 05:16:13 +00:00
|
|
|
use std::path::PathBuf;
|
2018-08-16 20:42:28 +00:00
|
|
|
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,
|
2018-08-16 16:49:29 +00:00
|
|
|
#[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>,
|
|
|
|
}
|
|
|
|
|
2018-08-16 20:42:28 +00:00
|
|
|
#[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-16 01:31:15 +00:00
|
|
|
fn main() -> Result<(), Error> {
|
|
|
|
let args = Opt::from_args();
|
|
|
|
let config: Config = serde_json::from_str(&args.config)?;
|
2018-08-16 15:18:45 +00:00
|
|
|
println!("{:?}", config);
|
2018-08-16 01:31:15 +00:00
|
|
|
|
|
|
|
let mut payload = String::new();
|
|
|
|
io::stdin().read_to_string(&mut payload)?;
|
|
|
|
let payload: Payload = serde_json::from_str(&payload)?;
|
|
|
|
|
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());
|
|
|
|
let signature = mac.result()
|
|
|
|
.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")
|
|
|
|
.ok_or(err_msg("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<_>>());
|
2018-08-16 16:49:29 +00:00
|
|
|
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-16 20:42:28 +00:00
|
|
|
let payload: GithubPayload = serde_json::from_str(&payload.body)?;
|
|
|
|
let mut target_path = PathBuf::from(env::var("DIP_WORKDIR")?);
|
2018-08-16 21:06:23 +00:00
|
|
|
target_path.push(&config.path);
|
2018-08-16 20:42:28 +00:00
|
|
|
Command::new("git")
|
|
|
|
.arg("clone")
|
|
|
|
.arg(&payload.repository.clone_url)
|
|
|
|
.arg("--recursive")
|
|
|
|
.arg("--depth")
|
|
|
|
.arg("1")
|
|
|
|
.arg(&target_path)
|
|
|
|
.output()?;
|
2018-08-16 01:31:15 +00:00
|
|
|
Ok(())
|
|
|
|
}
|