feat: add middleware to verify gitea webhooks
This commit is contained in:
parent
5ac86cc75c
commit
e8af456476
|
@ -1,11 +1,16 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"git.lumeweb.com/LumeWeb/gitea-github-proxy/config"
|
"git.lumeweb.com/LumeWeb/gitea-github-proxy/config"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -86,6 +91,51 @@ func loggingMiddleware(logger *zap.Logger) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func giteaVerifyWebhookMiddleware(cfg *config.Config, logger *zap.Logger) mux.MiddlewareFunc {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
signature := r.Header.Get("X-Gitea-Signature")
|
||||||
|
if signature == "" {
|
||||||
|
http.Error(w, "No signature provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedSignature, err := hex.DecodeString(signature)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error decoding signature", http.StatusBadRequest)
|
||||||
|
logger.Error("Error decoding signature", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error reading body", http.StatusBadRequest)
|
||||||
|
logger.Error("Error reading body", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(body io.ReadCloser) {
|
||||||
|
err := body.Close()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error closing body", zap.Error(err))
|
||||||
|
}
|
||||||
|
}(r.Body)
|
||||||
|
|
||||||
|
r.Body = io.NopCloser(bytes.NewBuffer(payload))
|
||||||
|
|
||||||
|
mac := hmac.New(sha256.New, []byte(cfg.GiteaWebHookSecret))
|
||||||
|
mac.Write(payload)
|
||||||
|
expectedMAC := mac.Sum(nil)
|
||||||
|
|
||||||
|
if !hmac.Equal(decodedSignature, expectedMAC) {
|
||||||
|
http.Error(w, "Invalid signature", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func addAuthStatusToRequestServ(status bool, r *http.Request, w http.ResponseWriter, next http.Handler) {
|
func addAuthStatusToRequestServ(status bool, r *http.Request, w http.ResponseWriter, next http.Handler) {
|
||||||
ctx := context.WithValue(r.Context(), AUTHED_CONTEXT_KEY, status)
|
ctx := context.WithValue(r.Context(), AUTHED_CONTEXT_KEY, status)
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
|
|
|
@ -38,6 +38,7 @@ type Config struct {
|
||||||
Oauth OauthConfig
|
Oauth OauthConfig
|
||||||
JwtPrivateKey PrivateKey
|
JwtPrivateKey PrivateKey
|
||||||
Domain string `mapstructure:"domain"`
|
Domain string `mapstructure:"domain"`
|
||||||
|
GiteaWebHookSecret string `mapstructure:"gitea_webhook_secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OauthConfig struct {
|
type OauthConfig struct {
|
||||||
|
|
Loading…
Reference in New Issue