package server import ( "encoding/json" "io" "log/slog" "net/http" "github.com/gin-gonic/gin" "git/palnet/slack-notifier/internal/gitea" "git/palnet/slack-notifier/internal/security" ) func (s *Server) handleGitea(c *gin.Context) { raw, err := io.ReadAll(c.Request.Body) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "cannot read body"}) return } if !security.VerifyHMACSHA256(s.cfg.GiteaWebhookSecret, raw, c.GetHeader("X-Gitea-Signature")) { slog.Warn("gitea signature verification failed") c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"}) return } event := c.GetHeader("X-Gitea-Event") notes, err := gitea.BuildNotifications(event, raw) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"}) return } sent := s.deliver(c.Request.Context(), notes) c.JSON(http.StatusOK, gin.H{"event": event, "matched": len(notes), "sent": sent}) } func (s *Server) handleNotion(c *gin.Context) { raw, err := io.ReadAll(c.Request.Body) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "cannot read body"}) return } // 1) Subscription verification handshake: Notion POSTs a verification_token once. // Capture it from logs and paste into NOTION_VERIFICATION_TOKEN. var probe struct { VerificationToken string `json:"verification_token"` } _ = json.Unmarshal(raw, &probe) if probe.VerificationToken != "" { slog.Warn("notion verification_token received — set this in NOTION_VERIFICATION_TOKEN", "verification_token", probe.VerificationToken) c.JSON(http.StatusOK, gin.H{"verification_token": probe.VerificationToken}) return } // 2) Normal events: verify signature against the verification token. if !security.VerifyHMACSHA256(s.cfg.NotionVerificationToken, raw, c.GetHeader("X-Notion-Signature")) { slog.Warn("notion signature verification failed") c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"}) return } notes, err := s.notion.BuildNotifications(c.Request.Context(), raw) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"}) return } sent := s.deliver(c.Request.Context(), notes) c.JSON(http.StatusOK, gin.H{"matched": len(notes), "sent": sent}) }