Arsen Musayelyan
891df91fee
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
90 lines
1.8 KiB
Go
90 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"go.arsenm.dev/logger/log"
|
|
"go.arsenm.dev/lure/internal/repos"
|
|
)
|
|
|
|
func handleWebhook(next http.Handler, sigCh chan<- struct{}) http.Handler {
|
|
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
|
if req.URL.Path == "/webhook" {
|
|
if req.Method != http.MethodPost {
|
|
res.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
if req.Header.Get("X-GitHub-Event") != "push" {
|
|
http.Error(res, "Only push events are accepted by this bot", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
err := verifySecure(req)
|
|
if err != nil {
|
|
http.Error(res, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
sigCh <- struct{}{}
|
|
return
|
|
}
|
|
|
|
next.ServeHTTP(res, req)
|
|
})
|
|
}
|
|
|
|
func verifySecure(req *http.Request) error {
|
|
sigStr := req.Header.Get("X-Hub-Signature-256")
|
|
sig, err := hex.DecodeString(strings.TrimPrefix(sigStr, "sha256="))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
secretStr, ok := os.LookupEnv("LURE_API_GITHUB_SECRET")
|
|
if !ok {
|
|
return errors.New("LURE_API_GITHUB_SECRET must be set to the secret used for setting up the github webhook")
|
|
}
|
|
secret := []byte(secretStr)
|
|
|
|
h := hmac.New(sha256.New, secret)
|
|
_, err = io.Copy(h, req.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !hmac.Equal(h.Sum(nil), sig) {
|
|
log.Warn("Insecure webhook request").
|
|
Str("from", req.RemoteAddr).
|
|
Bytes("sig", sig).
|
|
Bytes("hmac", h.Sum(nil)).
|
|
Send()
|
|
|
|
return errors.New("webhook signature mismatch")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func repoPullWorker(ctx context.Context, sigCh <-chan struct{}) {
|
|
for {
|
|
select {
|
|
case <-sigCh:
|
|
err := repos.Pull(ctx, gdb, cfg.Repos)
|
|
if err != nil {
|
|
log.Warn("Error while pulling repositories").Err(err).Send()
|
|
}
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|