init
This commit is contained in:
154
handlers/webhook.go
Normal file
154
handlers/webhook.go
Normal file
@ -0,0 +1,154 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code-review/config"
|
||||
"code-review/services"
|
||||
"code-review/services/platforms"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type WebhookHandler struct {
|
||||
reviewService *services.ReviewService
|
||||
}
|
||||
|
||||
func NewWebhookHandler(reviewService *services.ReviewService) *WebhookHandler {
|
||||
return &WebhookHandler{
|
||||
reviewService: reviewService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) HandleWebhook(c *gin.Context) {
|
||||
platform := c.Param("platform")
|
||||
log.Printf("收到 webhook 请求: platform=%s", platform)
|
||||
|
||||
// 验证 webhook 签名
|
||||
if !h.verifySignature(c, platform) {
|
||||
log.Printf("webhook 签名验证失败: platform=%s", platform)
|
||||
c.JSON(400, gin.H{"error": "无效的签名"})
|
||||
return
|
||||
}
|
||||
|
||||
// 解析请求体
|
||||
event, err := h.parseWebhookEvent(c, platform)
|
||||
if err != nil {
|
||||
log.Printf("解析 webhook 事件失败: platform=%s, error=%v", platform, err)
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 启动代码审查
|
||||
if err := h.reviewService.Review(event); err != nil {
|
||||
log.Printf("代码审查失败: platform=%s, error=%v", platform, err)
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("代码审查完成: platform=%s", platform)
|
||||
c.JSON(200, gin.H{"message": "success"})
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) verifySignature(c *gin.Context, platform string) bool {
|
||||
body, err := c.GetRawData()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
||||
|
||||
cfg := config.GetConfig()
|
||||
// 查找对应的平台配置
|
||||
var gitConfig config.GitConfig
|
||||
found := false
|
||||
for _, p := range cfg.Git {
|
||||
if p.Name == platform {
|
||||
gitConfig = p
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取签名
|
||||
signature := c.GetHeader(gitConfig.SignatureHeader)
|
||||
if signature == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
mac := hmac.New(sha256.New, []byte(gitConfig.Secret))
|
||||
mac.Write(body)
|
||||
expectedMAC := hex.EncodeToString(mac.Sum(nil))
|
||||
|
||||
return hmac.Equal([]byte(signature), []byte(expectedMAC)) || hmac.Equal([]byte(signature), []byte(gitConfig.Secret))
|
||||
}
|
||||
|
||||
func (h *WebhookHandler) parseWebhookEvent(c *gin.Context, platform string) (services.WebhookEvent, error) {
|
||||
cfg := config.GetConfig()
|
||||
// 查找对应的平台配置
|
||||
var platformConfig config.GitConfig
|
||||
found := false
|
||||
for _, p := range cfg.Git {
|
||||
if p.Name == platform {
|
||||
platformConfig = p
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, fmt.Errorf("不支持的平台: %s", platform)
|
||||
}
|
||||
|
||||
// 获取事件类型
|
||||
eventType := c.GetHeader(platformConfig.EventHeader)
|
||||
if eventType == "" {
|
||||
return nil, fmt.Errorf("未找到事件类型 header: %s", platformConfig.EventHeader)
|
||||
}
|
||||
|
||||
var event services.WebhookEvent
|
||||
switch platformConfig.Type {
|
||||
case "gogs":
|
||||
event = platforms.NewGogsEvent(
|
||||
platformConfig.APIBase,
|
||||
platformConfig.Token,
|
||||
eventType,
|
||||
)
|
||||
case "gitea":
|
||||
event = platforms.NewGiteaEvent(
|
||||
platformConfig.APIBase,
|
||||
platformConfig.Token,
|
||||
eventType,
|
||||
)
|
||||
//case "gitee":
|
||||
// event = &platforms.GiteeEvent{
|
||||
// ApiBase: platformConfig.APIBase,
|
||||
// Token: platformConfig.Token,
|
||||
// }
|
||||
case "gitlab":
|
||||
event = platforms.NewGitlabEvent(
|
||||
platformConfig.APIBase,
|
||||
platformConfig.Token,
|
||||
eventType,
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的平台: %s", platform)
|
||||
}
|
||||
|
||||
// 只处理 push 和 pull_request 事件
|
||||
//if eventType != "push" && eventType != "pull_request" {
|
||||
// return nil, fmt.Errorf("不支持的事件类型: %s", eventType)
|
||||
//}
|
||||
|
||||
if err := c.ShouldBindJSON(event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return event, nil
|
||||
}
|
Reference in New Issue
Block a user