From fd85de951ca3c51a1831c0b44bc63e582cd13e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Fri, 19 Apr 2024 20:49:31 +0200 Subject: [PATCH] WIP: Add support for forgejo webhooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime “pep” Buquet --- Cargo.toml | 1 + src/bot.rs | 4 ++-- src/main.rs | 4 ++-- src/web.rs | 65 +++++++++++++++++++++++++++++++++++++------------- src/webhook.rs | 27 +++++++++++++-------- 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a390afc..2902e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "AGPL-3.0+" [dependencies] clap = { version = "4.3", features = [ "cargo" ] } gitlab = "0.1610" +forgejo-api-types = "0.1" hyper = { version = "0.14", features = [ "full" ] } jid = { version = "*", features = [ "serde" ] } log = "0.4" diff --git a/src/bot.rs b/src/bot.rs index 4630d2a..8de5e87 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::webhook::{format_webhook, WebHook}; +use crate::webhook::{format_webhook, GitlabHook}; use log::debug; use xmpp::parsers::message::MessageType; @@ -74,7 +74,7 @@ impl XmppClient { } } - pub async fn webhook(&mut self, wh: WebHook) { + pub async fn webhook(&mut self, wh: GitlabHook) { debug!("Received Webhook"); if let Some(display) = format_webhook(&wh) { debug!("Webhook: {}", display); diff --git a/src/main.rs b/src/main.rs index 964be89..c989e4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ mod webhook; use crate::bot::XmppClient; use crate::error::Error; use crate::web::webhooks; -use crate::webhook::WebHook; +use crate::webhook::GitlabHook; use std::convert::Infallible; use std::fs::File; @@ -133,7 +133,7 @@ async fn main() -> Result { } }; - let (value_tx, mut value_rx) = mpsc::unbounded_channel::(); + let (value_tx, mut value_rx) = mpsc::unbounded_channel::(); if let Some(token) = config.webhook_token { let value_tx = Arc::new(Mutex::new(value_tx)); diff --git a/src/web.rs b/src/web.rs index 5cb843b..4791157 100644 --- a/src/web.rs +++ b/src/web.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . use crate::error::Error; -use crate::webhook::WebHook; +use crate::webhook::{Hook, ForgejoHook, GitlabHook}; use std::convert::Infallible; use std::str::from_utf8; @@ -35,42 +35,73 @@ fn error_res(e: E) -> Result, Infallible> { Ok(res) } -async fn webhooks_inner(req: Request, token: &str) -> Result { +async fn webhooks_inner(req: Request, token: &str) -> Result { match req.method() { &Method::POST => (), _ => return Err(Error::MethodMismatch), } debug!("Headers: {:?}", req.headers()); - let headers = req.headers(); - if let Some(content_type) = headers.get(header::CONTENT_TYPE) - && let Some(header_token) = headers.get("X-Gitlab-Token") - { - if content_type != "application/json" { - return Err(Error::InvalidContentType); - } - - if header_token != token { - return Err(Error::InvalidToken); - } - } + /* let tmp = body::to_bytes(req.into_body()).await?; let text: &str = from_utf8(&tmp)?; - Ok(serde_json::from_str(text)?) + debug!("FOO0 text: {:?}", text); + let json = serde_json::from_str(text)?; + debug!("FOO0 json: {:?}", json); + + return Err(Error::InvalidToken); // XXX: Test. + */ + + if let Some(content_type) = headers.get(header::CONTENT_TYPE) + && content_type != "application/json" + { + return Err(Error::InvalidContentType); + } + + if let Some(header_token) = headers.get("X-Gilab-Token") { + debug!("FOO1: X-Gitlab-Token"); + if header_token != token { + Err(Error::InvalidToken) + } else { + let tmp = body::to_bytes(req.into_body()).await?; + let text: &str = from_utf8(&tmp)?; + let hook: GitlabHook = serde_json::from_str(text)?; + debug!("FOO1: {:?}", hook); + Ok(Hook::Gitlab(hook)) + } + } else if let Some(header_token) = headers.get("Authorization") { + debug!("FOO3: Authorization"); + if header_token != token { + Err(Error::InvalidToken) + } else { + let tmp = body::to_bytes(req.into_body()).await?; + let text: &str = from_utf8(&tmp)?; + debug!("FOO3 text: {:?}", text); + let hook: ForgejoHook = serde_json::from_str(text)?; + debug!("FOO3 json: {:?}", hook); + Ok(Hook::Forgejo(hook)) + } + } else { + debug!("FOO3: else"); + Err(Error::InvalidToken) + } } pub async fn webhooks( req: Request, token: String, - value_tx: Arc>>, + value_tx: Arc>>, ) -> Result, Infallible> { match webhooks_inner(req, token.as_ref()).await { Ok(wh) => { debug!("Passed: {:?}", wh); - value_tx.lock().unwrap().send(wh).unwrap(); + match wh { + Hook::Gitlab(glh) => value_tx.lock().unwrap().send(glh).unwrap(), + _ => (), + } Ok(Response::new("Hello world".into())) } diff --git a/src/webhook.rs b/src/webhook.rs index f4a348a..4985bb5 100644 --- a/src/webhook.rs +++ b/src/webhook.rs @@ -13,12 +13,19 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -pub use gitlab::webhooks::{IssueAction, MergeRequestAction, WebHook, WikiPageAction}; +pub use gitlab::webhooks::{IssueAction, MergeRequestAction, WebHook as GitlabHook, WikiPageAction}; +pub use forgejo_api_types::types::api::hook::Hook as ForgejoHook; use log::debug; -pub fn format_webhook(wh: &WebHook) -> Option { - Some(match wh { - WebHook::Push(push) => { +#[derive(Debug)] +pub enum Hook { + Forgejo(ForgejoHook), + Gitlab(GitlabHook), +} + +pub fn format_webhook(glh: &GitlabHook) -> Option { + Some(match glh { + GitlabHook::Push(push) => { if push.ref_ != "refs/heads/main" { // Ignore: Action not on 'main' branch return None; @@ -45,7 +52,7 @@ pub fn format_webhook(wh: &WebHook) -> Option { } text } - WebHook::Issue(issue) => { + GitlabHook::Issue(issue) => { let action = match issue.object_attributes.action { Some(IssueAction::Update) => return None, Some(IssueAction::Open) => "opened", @@ -68,7 +75,7 @@ pub fn format_webhook(wh: &WebHook) -> Option { .unwrap_or("".to_owned()) ) } - WebHook::MergeRequest(merge_req) => { + GitlabHook::MergeRequest(merge_req) => { let action = match merge_req.object_attributes.action { Some(MergeRequestAction::Update) => return None, Some(MergeRequestAction::Open) => "opened", @@ -93,7 +100,7 @@ pub fn format_webhook(wh: &WebHook) -> Option { .unwrap_or("".to_owned()) ) } - WebHook::Note(note) => { + GitlabHook::Note(note) => { if let Some(_) = note.snippet { return None; } @@ -120,11 +127,11 @@ pub fn format_webhook(wh: &WebHook) -> Option { unreachable!() } } - WebHook::Build(build) => { + GitlabHook::Build(build) => { println!("Build: {:?}", build); return None; } - WebHook::WikiPage(page) => { + GitlabHook::WikiPage(page) => { let action = match page.object_attributes.action { WikiPageAction::Update => "updated", WikiPageAction::Create => "created", @@ -138,7 +145,7 @@ pub fn format_webhook(wh: &WebHook) -> Option { page.object_attributes.url, ) } - _wh => { + _glh => { debug!("Webhook not supported"); return None; }