Adapt to new versions of rocket and clap

Use clap `3.0.0-beta.5` and rocket `0.5.0-rc.1`.
This commit is contained in:
finga 2021-11-03 13:09:44 +01:00
parent 41d8efe8a8
commit 5a88fb892b
3 changed files with 1169 additions and 437 deletions

1525
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@ description = "Trigger scripts via http(s) requests"
tls = ["rocket/tls"] tls = ["rocket/tls"]
[dependencies] [dependencies]
rocket = "0.4" rocket = "0.5.0-rc.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_yaml = "0.8" serde_yaml = "0.8"
@ -27,7 +27,7 @@ hex = "0.4"
ipnet = { version = "2.3", features = ["serde"] } ipnet = { version = "2.3", features = ["serde"] }
thiserror = "1.0" thiserror = "1.0"
run_script = "0.7" run_script = "0.7"
clap = "3.0.0-beta.4" clap = "3.0.0-beta.5"
[package.metadata.deb] [package.metadata.deb]
extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently." extended-description = "Webhookey receives requests in form of a so called Webhook as for example sent by Gitea. Those requests are matched against configured filters, if a filter matches, values from the header and the body can be passed to scripts as parameters which are then executed subsequently."

View file

@ -1,7 +1,7 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use clap::{crate_authors, crate_version, AppSettings, Clap}; use clap::{crate_authors, crate_version, AppSettings, Parser};
use hmac::{Hmac, Mac, NewMac}; use hmac::{Hmac, Mac, NewMac};
use ipnet::IpNet; use ipnet::IpNet;
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
@ -15,12 +15,13 @@ use nom::{
}; };
use regex::Regex; use regex::Regex;
use rocket::{ use rocket::{
data::{self, FromDataSimple}, data::{FromData, ToByteUnit},
fairing::AdHoc, futures::TryFutureExt,
http::{HeaderMap, Status}, http::{HeaderMap, Status},
post, routes, Data, outcome::Outcome::{self, Failure, Success},
Outcome::{Failure, Success}, post, routes,
Request, Response, State, tokio::io::AsyncReadExt,
Data, Request, State,
}; };
use run_script::ScriptOptions; use run_script::ScriptOptions;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -30,7 +31,7 @@ use thiserror::Error;
use std::{ use std::{
collections::HashMap, collections::HashMap,
fs::File, fs::File,
io::{BufReader, Read}, io::BufReader,
net::{IpAddr, Ipv4Addr, SocketAddr}, net::{IpAddr, Ipv4Addr, SocketAddr},
}; };
@ -54,17 +55,16 @@ enum WebhookeyError {
Regex(regex::Error), Regex(regex::Error),
} }
#[derive(Clap, Debug)] #[derive(Debug, Parser)]
enum Command { enum Command {
/// Verifies if the configuration can be parsed without errors /// Verifies if the configuration can be parsed without errors
Configtest, Configtest,
} }
#[derive(Clap, Debug)] #[derive(Debug, Parser)]
#[clap( #[clap(
version = crate_version!(), version = crate_version!(),
author = crate_authors!(", "), author = crate_authors!(", "),
global_setting = AppSettings::ColoredHelp,
global_setting = AppSettings::InferSubcommands, global_setting = AppSettings::InferSubcommands,
global_setting = AppSettings::PropagateVersion, global_setting = AppSettings::PropagateVersion,
)] )]
@ -242,15 +242,16 @@ struct Hooks {
} }
impl Hooks { impl Hooks {
fn get_commands(request: &Request, data: Data) -> Result<Self, WebhookeyError> { async fn get_commands(request: &Request<'_>, data: Data<'_>) -> Result<Self, WebhookeyError> {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let size = data let size = data
.open() .open(256_i32.kilobytes())
.read_to_end(&mut buffer) .read_to_end(&mut buffer)
.map_err(WebhookeyError::Io)?; .map_err(WebhookeyError::Io)
.await?;
info!("Data of size {} received", size); info!("Data of size {} received", size);
let config = request.guard::<State<Config>>().unwrap(); // should never fail let config = request.guard::<&State<Config>>().await.unwrap(); // should never fail
let mut valid = false; let mut valid = false;
let mut result = HashMap::new(); let mut result = HashMap::new();
let client_ip = &request let client_ip = &request
@ -318,11 +319,15 @@ impl Hooks {
} }
} }
impl FromDataSimple for Hooks { #[rocket::async_trait]
impl<'r> FromData<'r> for Hooks {
type Error = WebhookeyError; type Error = WebhookeyError;
fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> { async fn from_data(
match Hooks::get_commands(request, data) { request: &'r Request<'_>,
data: Data<'r>,
) -> Outcome<Self, (Status, Self::Error), Data<'r>> {
match Hooks::get_commands(request, data).await {
Ok(hooks) => { Ok(hooks) => {
if hooks.inner.is_empty() { if hooks.inner.is_empty() {
let client_ip = &request let client_ip = &request
@ -440,7 +445,7 @@ fn get_string(value: &serde_json::Value) -> Result<String, WebhookeyError> {
} }
#[post("/", format = "json", data = "<hooks>")] #[post("/", format = "json", data = "<hooks>")]
fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result<Response<'a>> { async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Status {
info!("Post request received from: {}", address); info!("Post request received from: {}", address);
hooks.inner.iter().for_each(|(name, command)| { hooks.inner.iter().for_each(|(name, command)| {
@ -458,7 +463,7 @@ fn receive_hook<'a>(address: SocketAddr, hooks: Hooks) -> Result<Response<'a>> {
} }
}); });
Ok(Response::new()) Status::Ok
} }
fn get_config() -> Result<File> { fn get_config() -> Result<File> {
@ -494,7 +499,8 @@ fn get_config() -> Result<File> {
bail!("No configuration file found."); bail!("No configuration file found.");
} }
fn main() -> Result<()> { #[rocket::main]
async fn main() -> Result<()> {
env_logger::init(); env_logger::init();
let cli: Opts = Opts::parse(); let cli: Opts = Opts::parse();
@ -512,12 +518,11 @@ fn main() -> Result<()> {
return Ok(()); return Ok(());
} }
rocket::ignite() rocket::build()
.mount("/", routes![receive_hook]) .mount("/", routes![receive_hook])
.attach(AdHoc::on_attach("webhookey config", move |rocket| { .manage(config)
Ok(rocket.manage(config)) .launch()
})) .await?;
.launch();
Ok(()) Ok(())
} }
@ -527,12 +532,12 @@ mod tests {
use super::*; use super::*;
use rocket::{ use rocket::{
http::{ContentType, Header}, http::{ContentType, Header},
local::Client, local::asynchronous::Client,
}; };
use serde_json::json; use serde_json::json;
#[test] #[rocket::async_test]
fn secret() { async fn secret() {
let mut hooks = HashMap::new(); let mut hooks = HashMap::new();
hooks.insert( hooks.insert(
@ -551,13 +556,11 @@ mod tests {
let config = Config { hooks: hooks }; let config = Config { hooks: hooks };
let rocket = rocket::ignite() let rocket = rocket::build()
.mount("/", routes![receive_hook]) .mount("/", routes![receive_hook])
.attach(AdHoc::on_attach("webhookey config", move |rocket| { .manage(config);
Ok(rocket.manage(config))
}));
let client = Client::new(rocket).unwrap(); let client = Client::tracked(rocket).await.unwrap();
let response = client let response = client
.post("/") .post("/")
.header(Header::new( .header(Header::new(
@ -569,7 +572,7 @@ mod tests {
.body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap())
.dispatch(); .dispatch();
assert_eq!(response.status(), Status::NotFound); assert_eq!(response.await.status(), Status::NotFound);
let response = client let response = client
.post("/") .post("/")
@ -579,7 +582,7 @@ mod tests {
.body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap()) .body(&serde_json::to_string(&json!({ "foo": "bar" })).unwrap())
.dispatch(); .dispatch();
assert_eq!(response.status(), Status::Unauthorized); assert_eq!(response.await.status(), Status::Unauthorized);
let response = client let response = client
.post("/") .post("/")
@ -592,7 +595,7 @@ mod tests {
.body(r#"{ "not_secret": "invalid" "#) .body(r#"{ "not_secret": "invalid" "#)
.dispatch(); .dispatch();
assert_eq!(response.status(), Status::BadRequest); assert_eq!(response.await.status(), Status::BadRequest);
let response = client let response = client
.post("/") .post("/")
@ -601,7 +604,7 @@ mod tests {
.remote("127.0.0.1:8000".parse().unwrap()) .remote("127.0.0.1:8000".parse().unwrap())
.dispatch(); .dispatch();
assert_eq!(response.status(), Status::Unauthorized); assert_eq!(response.await.status(), Status::Unauthorized);
} }
#[test] #[test]