Refracto webhook

This commit is contained in:
SebClem 2023-01-05 16:14:38 +01:00
parent c87fb882b4
commit 44ac4deecf
Signed by: sebclem
GPG Key ID: 5A4308F6A359EA50
4 changed files with 119 additions and 54 deletions

View File

@ -2,87 +2,58 @@ package controllers
import (
"bytes"
"crypto/hmac"
"io/ioutil"
"net/http"
hmacService "git.sebclem.fr/sebclem/renovate-manager/services/hmac"
giteaService "git.sebclem.fr/sebclem/renovate-manager/services/webhook/gitea"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
type WebhookController struct{}
type WebhookController struct {
WebhookSecret string
RenovateUsername string
}
func (ctl WebhookController) HandleGiteaWebhook(c *gin.Context) {
func (ctrl WebhookController) HandleGiteaWebhook(c *gin.Context) {
r := c.Request
signature := r.Header.Get("X-Gitea-Signature")
body, err := ioutil.ReadAll(r.Body)
if err != nil {
c.AbortWithStatus(500)
c.AbortWithStatus(http.StatusInternalServerError)
return
}
expectedSignature := hmacService.CalculateHMAC("test", body)
if signature == "" || !hmac.Equal([]byte(signature), []byte(expectedSignature)) {
logrus.Error("Signature missmatch, Abort !")
c.AbortWithStatus(401)
if !hmacService.CompareSignature(body, signature, ctrl.WebhookSecret) {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
// Reset the request body so it can be Bind to json
// Reset the request body so it can be read again by BindJSON
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
switch r.Header.Get("X-Gitea-Event") {
case "push":
logrus.Info("Received PUSH webhook")
case "create":
logrus.Info("Received CREATE webhook")
case "delete":
logrus.Info("Received DELETE webhook")
case "issues":
logrus.Info("Received ISSUES webhook")
logrus.Debug("Received PUSH webhook")
case "issue_comment":
logrus.Info("Received ISSUE_COMMENT webhook")
case "pull_request":
logrus.Info("Received PULL_REQUEST webhook")
var data PullRequestWebhook
logrus.Debug("Received ISSUE_COMMENT webhook")
var data giteaService.IssueComentWebhook
if err := c.BindJSON(&data); err == nil {
logrus.Info("All good")
giteaService.HandleGiteaIssueComment(data, ctrl.RenovateUsername)
c.String(201, "")
} else {
logrus.Error("Fail to parse json")
}
case "pull_request":
logrus.Debug("Received PULL_REQUEST webhook")
var data giteaService.PullRequestWebhook
if err := c.BindJSON(&data); err == nil {
giteaService.HandleGiteaPullRequest(data, ctrl.RenovateUsername)
c.String(201, "")
} else {
logrus.Error("Fail to parse json")
}
default:
logrus.Warn("Received UNKNOWN webhook")
}
// ctx.String(201, "")
}
type PullRequestWebhook struct {
Action string `json:"action"`
Number int `json:"number"`
PullRequest PullRequest `json:"pull_request"`
Repository Repository `json:"repository"`
Sender User `json:"sender"`
}
type PullRequest struct {
Id int `json:"id"`
Url string `json:"url"`
Number uint64 `json:"number"`
User User `json:"user"`
}
type User struct {
Id int `json:"id"`
Login string `json:"login"`
Username string `json:"username"`
}
type Repository struct {
Id int `json:"id"`
Owner User `json:"owner"`
Name string `json:"name"`
FullName string `json:"full_name"`
}

View File

@ -6,6 +6,6 @@ import (
)
func LoadWebhook(g *gin.RouterGroup) {
controller := new(controllers.WebhookController)
controller := controllers.WebhookController{WebhookSecret: "test", RenovateUsername: "renovate-bot"}
g.POST("gitea", controller.HandleGiteaWebhook)
}

View File

@ -4,6 +4,8 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"github.com/sirupsen/logrus"
)
func CalculateHMAC(secret string, message []byte) string {
@ -12,3 +14,13 @@ func CalculateHMAC(secret string, message []byte) string {
h.Write(message)
return hex.EncodeToString(h.Sum(nil))
}
func CompareSignature(body []byte, signature string, secret string) bool {
expectedSignature := CalculateHMAC(secret, body)
if signature == "" || !hmac.Equal([]byte(signature), []byte(expectedSignature)) {
logrus.Error("Signature missmatch, Abort !")
return false
}
return true
}

View File

@ -0,0 +1,82 @@
package gitea
import (
"strings"
"github.com/sirupsen/logrus"
)
func HandleGiteaPullRequest(data PullRequestWebhook, renovateUsername string) {
if !isFromRenovate(data.Sender, renovateUsername) {
if isEditOnRenovatePR(data, renovateUsername) {
logrus.Info("Edit on renovate PR, launch renovate")
logrus.Info("Repo: ", data.Repository.FullName, " PR: ", data.Number)
}
}
}
func HandleGiteaIssueComment(data IssueComentWebhook, renovateUsername string) {
if !isFromRenovate(data.Sender, renovateUsername) {
if strings.Contains(data.Comment.Body, "@"+renovateUsername) {
logrus.Info("Mention in comment, launch renovate")
logrus.Info("Repo: ", data.Repository.FullName)
}
}
}
func isFromRenovate(sender User, renovateUsername string) bool {
return sender.Username == renovateUsername
}
func isRenovatePR(data PullRequest, renovateUsername string) bool {
return data.User.Username == renovateUsername
}
func isEditOnRenovatePR(data PullRequestWebhook, renovateUsername string) bool {
if data.Action == "edited" {
return isRenovatePR(data.PullRequest, renovateUsername)
}
return false
}
type PullRequestWebhook struct {
Action string `json:"action"`
Number int `json:"number"`
PullRequest PullRequest `json:"pull_request"`
Repository Repository `json:"repository"`
Sender User `json:"sender"`
}
type IssueComentWebhook struct {
Action string `json:"action"`
Comment Comment `json:"comment"`
Repository Repository `json:"repository"`
Sender User `json:"sender"`
IsPull bool `json:"is_pull"`
}
type PullRequest struct {
Id int `json:"id"`
Url string `json:"url"`
Number uint64 `json:"number"`
User User `json:"user"`
}
type Comment struct {
Id int `json:"id"`
User User `json:"user"`
Body string `json:"body"`
}
type User struct {
Id int `json:"id"`
Login string `json:"login"`
Username string `json:"username"`
}
type Repository struct {
Id int `json:"id"`
Owner User `json:"owner"`
Name string `json:"name"`
FullName string `json:"full_name"`
}