From fd361fd43a5b344bfb1c6da66c76022b2b2c2bff Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 9 Oct 2020 08:15:39 +0000 Subject: [PATCH] add gitea --- examples/dotenv | 2 + gitea.go | 7 ++ internal/webhooks/gitea/gitea.go | 100 +++++++++++++++++++++++++++++ internal/webhooks/gitea/payload.go | 44 +++++++++++++ main.go | 13 +++- 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 gitea.go create mode 100644 internal/webhooks/gitea/gitea.go create mode 100644 internal/webhooks/gitea/payload.go diff --git a/examples/dotenv b/examples/dotenv index 5c9186c..41e0915 100644 --- a/examples/dotenv +++ b/examples/dotenv @@ -1,2 +1,4 @@ +PORT=4483 GITHUB_SECRET=xxxxxxxxxxxxxxxxxxxxxx +GITEA_SECRET=xxxxxxxxxxxxxxxxxxxxxx BITBUCKET_SECRET=xxxxxxxxxxxxxxxxxxxxxx diff --git a/gitea.go b/gitea.go new file mode 100644 index 0000000..50dbc41 --- /dev/null +++ b/gitea.go @@ -0,0 +1,7 @@ +// +build !nobitbucket + +package main + +import ( + _ "git.ryanburnette.com/ryanburnette/git-deploy/internal/webhooks/gitea" +) diff --git a/internal/webhooks/gitea/gitea.go b/internal/webhooks/gitea/gitea.go new file mode 100644 index 0000000..067b614 --- /dev/null +++ b/internal/webhooks/gitea/gitea.go @@ -0,0 +1,100 @@ +package gitea + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strings" + + "git.ryanburnette.com/ryanburnette/git-deploy/internal/options" + "git.ryanburnette.com/ryanburnette/git-deploy/internal/webhooks" + + "github.com/go-chi/chi" + "github.com/google/go-github/v32/github" +) + +func init() { + var secret string + name := "gitea" + options.ServerFlags.StringVar( + &secret, fmt.Sprintf("%s-secret", name), "", + fmt.Sprintf( + "secret for %s webhooks (same as %s_SECRET=)", + name, strings.ToUpper(name)), + ) + webhooks.AddProvider("gitea", InitWebhook("gitea", &secret, "GITEA_SECRET")) +} + +// InitWebhook prepares the webhook router. +// It should be called after arguments are parsed and ENVs are set.InitWebhook +func InitWebhook(providername string, secret *string, envname string) func() { + return func() { + if "" == *secret { + *secret = os.Getenv(envname) + } + if "" == *secret { + fmt.Fprintf(os.Stderr, "skipped route for missing %s\n", envname) + return + } + secretB := []byte(*secret) + webhooks.AddRouteHandler(providername, func(router chi.Router) { + router.Post("/", func(w http.ResponseWriter, r *http.Request) { + r.Body = http.MaxBytesReader(w, r.Body, options.DefaultMaxBodySize) + + payload, err := ioutil.ReadAll(r.Body) + if err != nil { + // if there's a read error, it should have been handled already by the MaxBytesReader + return + } + + sig := "sha256=" + r.Header.Get("X_GITEA_SIGNATURE") + if err := github.ValidateSignature(sig, payload, secretB); nil != err { + log.Printf("invalid gitea signature: error: %s\n", err) + http.Error(w, "invalid gitea signature", http.StatusBadRequest) + return + } + + info := Webhook{} + if err := json.Unmarshal(payload, &info); nil != err { + log.Printf("invalid gitea payload: error: %s\n%s\n", err, string(payload)) + http.Error(w, "invalid gitea payload", http.StatusBadRequest) + return + } + + var tag string + var branch string + ref := info.Ref // refs/heads/master + parts := strings.Split(ref, "/") + refType := parts[1] // refs/[heads]/master + prefixLen := len("refs/") + len(refType) + len("/") + refName := ref[prefixLen:] + switch refType { + case "tags": + refType = "tag" + tag = refName + case "heads": + refType = "branch" + branch = refName + default: + refType = "unknown" + } + + webhooks.Hook(webhooks.Ref{ + HTTPSURL: info.Repository.CloneURL, + SSHURL: info.Repository.SSHURL, + Rev: info.After, + Ref: ref, + RefType: refType, + RefName: refName, + Branch: branch, + Tag: tag, + Repo: info.Repository.Name, + Owner: info.Repository.Owner.Login, + }) + }) + }) + } +} diff --git a/internal/webhooks/gitea/payload.go b/internal/webhooks/gitea/payload.go new file mode 100644 index 0000000..d8c8379 --- /dev/null +++ b/internal/webhooks/gitea/payload.go @@ -0,0 +1,44 @@ +package gitea + +// ref +// after +// repository.name +// repository.full_name +// repository.clone_url + +// See https://docs.gitea.io/en-us/webhooks/ +// and https://mholt.github.io/json-to-go/ +type Webhook struct { + Secret string `json:"secret"` + Ref string `json:"ref"` + Before string `json:"before"` + After string `json:"after"` + CompareURL string `json:"compare_url"` + Repository struct { + ID int `json:"id"` + Owner struct { + ID int `json:"id"` + Login string `json:"login"` + FullName string `json:"full_name"` + Email string `json:"email"` + AvatarURL string `json:"avatar_url"` + Username string `json:"username"` + } `json:"owner"` + Name string `json:"name"` + FullName string `json:"full_name"` + Description string `json:"description"` + Private bool `json:"private"` + Fork bool `json:"fork"` + HTMLURL string `json:"html_url"` + SSHURL string `json:"ssh_url"` + CloneURL string `json:"clone_url"` + Website string `json:"website"` + StarsCount int `json:"stars_count"` + ForksCount int `json:"forks_count"` + WatchersCount int `json:"watchers_count"` + OpenIssuesCount int `json:"open_issues_count"` + DefaultBranch string `json:"default_branch"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } `json:"repository"` +} diff --git a/main.go b/main.go index 3337eea..de7fd88 100644 --- a/main.go +++ b/main.go @@ -61,7 +61,7 @@ func init() { runOpts = options.Server runFlags = options.ServerFlags initFlags = options.InitFlags - runFlags.StringVar(&runOpts.Addr, "listen", ":3000", "the address and port on which to listen") + runFlags.StringVar(&runOpts.Addr, "listen", "", "the address and port on which to listen (default :4483)") runFlags.BoolVar(&runOpts.TrustProxy, "trust-proxy", false, "trust X-Forwarded-For header") runFlags.BoolVar(&runOpts.Compress, "compress", true, "enable compression for text,html,js,css,etc") runFlags.StringVar( @@ -107,6 +107,17 @@ func main() { os.Exit(1) return } + if 0 == len(runOpts.Addr) { + runOpts.Addr = os.Getenv("LISTEN") + } + if 0 == len(runOpts.Addr) { + runOpts.Addr = "localhost:" + os.Getenv("PORT") + } + if 0 == len(runOpts.Addr) { + fmt.Printf("--listen <[addr]:port> is a required flag") + os.Exit(1) + return + } webhooks.MustRegisterAll() serve() default: