feat: REST API: list all webhooks created by user
This commit is contained in:
parent
5d4977f421
commit
e423ccc0ee
1 changed files with 200 additions and 0 deletions
200
src/ctx/api/v1/gitea.rs
Normal file
200
src/ctx/api/v1/gitea.rs
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use actix_web::web;
|
||||||
|
use actix_web::HttpRequest;
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sha2::Sha256;
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
|
use crate::ctx::Ctx;
|
||||||
|
|
||||||
|
use crate::errors::ServiceResult;
|
||||||
|
|
||||||
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct CommitPerson {
|
||||||
|
name: String,
|
||||||
|
email: String,
|
||||||
|
username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct Commit {
|
||||||
|
id: String,
|
||||||
|
message: String,
|
||||||
|
url: String,
|
||||||
|
author: CommitPerson,
|
||||||
|
committer: CommitPerson,
|
||||||
|
verification: serde_json::Value,
|
||||||
|
timestamp: String,
|
||||||
|
added: serde_json::Value,
|
||||||
|
removed: serde_json::Value,
|
||||||
|
modified: serde_json::Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct Person {
|
||||||
|
id: usize,
|
||||||
|
login: String,
|
||||||
|
full_name: String,
|
||||||
|
email: String,
|
||||||
|
avatar_url: String,
|
||||||
|
language: String,
|
||||||
|
is_admin: bool,
|
||||||
|
last_login: String,
|
||||||
|
created: String,
|
||||||
|
restricted: bool,
|
||||||
|
active: bool,
|
||||||
|
prohibit_login: bool,
|
||||||
|
location: String,
|
||||||
|
website: String,
|
||||||
|
description: String,
|
||||||
|
visibility: String,
|
||||||
|
followers_count: usize,
|
||||||
|
following_count: usize,
|
||||||
|
starred_repos_count: usize,
|
||||||
|
username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct Permissions {
|
||||||
|
admin: bool,
|
||||||
|
push: bool,
|
||||||
|
pull: bool,
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct InternalTracker {
|
||||||
|
enable_time_tracker: bool,
|
||||||
|
allow_only_contributors_to_track_time: bool,
|
||||||
|
enable_issue_dependencies: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct Repository {
|
||||||
|
id: usize,
|
||||||
|
owner: Person,
|
||||||
|
name: String,
|
||||||
|
full_name: String,
|
||||||
|
description: String,
|
||||||
|
empty: bool,
|
||||||
|
private: bool,
|
||||||
|
fork: bool,
|
||||||
|
template: bool,
|
||||||
|
parent: Option<serde_json::Value>,
|
||||||
|
mirror: bool,
|
||||||
|
size: usize,
|
||||||
|
html_url: String,
|
||||||
|
ssh_url: String,
|
||||||
|
clone_url: String,
|
||||||
|
original_url: String,
|
||||||
|
website: String,
|
||||||
|
stars_count: usize,
|
||||||
|
forks_count: usize,
|
||||||
|
watchers_count: usize,
|
||||||
|
open_issues_count: usize,
|
||||||
|
open_pr_counter: usize,
|
||||||
|
release_counter: usize,
|
||||||
|
default_branch: String,
|
||||||
|
archived: bool,
|
||||||
|
created_at: String,
|
||||||
|
updated_at: String,
|
||||||
|
permissions: Permissions,
|
||||||
|
has_issues: bool,
|
||||||
|
internal_tracker: InternalTracker,
|
||||||
|
has_wiki: bool,
|
||||||
|
has_pull_requests: bool,
|
||||||
|
has_projects: bool,
|
||||||
|
ignore_whitespace_conflicts: bool,
|
||||||
|
allow_merge_commits: bool,
|
||||||
|
allow_rebase: bool,
|
||||||
|
allow_rebase_explicit: bool,
|
||||||
|
allow_squash_merge: bool,
|
||||||
|
default_merge_style: String,
|
||||||
|
avatar_url: String,
|
||||||
|
internal: bool,
|
||||||
|
mirror_interval: String,
|
||||||
|
mirror_updated: String,
|
||||||
|
repo_transfer: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
|
pub struct WebhookPayload {
|
||||||
|
#[serde(rename(serialize = "ref", deserialize = "ref"))]
|
||||||
|
reference: String,
|
||||||
|
before: String,
|
||||||
|
after: String,
|
||||||
|
compare_url: String,
|
||||||
|
repository: Repository,
|
||||||
|
pusher: Person,
|
||||||
|
sender: Person,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ctx {
|
||||||
|
pub async fn process_webhook(
|
||||||
|
&self,
|
||||||
|
body: &web::Bytes,
|
||||||
|
req: &HttpRequest,
|
||||||
|
auth_token: &str,
|
||||||
|
) -> ServiceResult<()> {
|
||||||
|
let headers = req.headers();
|
||||||
|
let _uuid = headers.get("X-Gitea-Delivery").unwrap();
|
||||||
|
let sig = headers.get("X-Gitea-Signature").unwrap();
|
||||||
|
let sig = hex::decode(sig).unwrap();
|
||||||
|
let event_type = headers.get("X-Gitea-Event").unwrap();
|
||||||
|
|
||||||
|
let payload: WebhookPayload = serde_json::from_slice(&body).unwrap();
|
||||||
|
|
||||||
|
let hook = self.db.get_webhook(auth_token).await?;
|
||||||
|
|
||||||
|
for url in [
|
||||||
|
&payload.repository.html_url,
|
||||||
|
&payload.repository.ssh_url,
|
||||||
|
&payload.repository.clone_url,
|
||||||
|
] {
|
||||||
|
if self.db.site_with_repository_exists(url).await? {
|
||||||
|
let mut mac = HmacSha256::new_from_slice(hook.gitea_webhook_secret.as_bytes())
|
||||||
|
.expect("HMAC can take key of any size");
|
||||||
|
mac.update(&body);
|
||||||
|
mac.verify_slice(&sig[..]).unwrap();
|
||||||
|
|
||||||
|
let site = self.db.get_site_from_repo_url(url).await?;
|
||||||
|
if payload.reference.contains(&site.branch) {
|
||||||
|
info!(
|
||||||
|
"[webhook][forgejo/gitea] received update {:?} from {url} repository on deployed branch",
|
||||||
|
event_type
|
||||||
|
);
|
||||||
|
self.update_site(&site.site_secret, Some(site.branch))
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"[webhook][forgejo/gitea] received update {:?} from {url} repository on non-deployed branch {}",
|
||||||
|
event_type,
|
||||||
|
payload.reference
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn!(
|
||||||
|
"[webhook][forgejo/gitea] stray update from {} repository",
|
||||||
|
payload.repository.html_url
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue