diff --git a/cmd/lure-api-server/badge-logo.txt b/cmd/lure-api-server/badge-logo.txt new file mode 100644 index 0000000..37767cc --- /dev/null +++ b/cmd/lure-api-server/badge-logo.txt @@ -0,0 +1 @@ +data:image/png;base64,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 \ No newline at end of file diff --git a/cmd/lure-api-server/badge.go b/cmd/lure-api-server/badge.go new file mode 100644 index 0000000..5c764bd --- /dev/null +++ b/cmd/lure-api-server/badge.go @@ -0,0 +1,59 @@ +package main + +import ( + _ "embed" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/go-chi/chi/v5" + "github.com/jmoiron/sqlx" + "go.elara.ws/lure/internal/db" +) + +//go:embed badge-logo.txt +var logoData string + +var _ http.HandlerFunc + +func handleBadge(gdb *sqlx.DB) http.HandlerFunc { + return func(res http.ResponseWriter, req *http.Request) { + repo := chi.URLParam(req, "repo") + name := chi.URLParam(req, "pkg") + + pkg, err := db.GetPkg(gdb, "name = ? AND repository = ?", name, repo) + if err != nil { + http.Error(res, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(res, req, genBadgeURL(pkg.Name, genVersion(pkg)), http.StatusFound) + } +} + +func genVersion(pkg *db.Package) string { + sb := strings.Builder{} + if pkg.Epoch != 0 { + sb.WriteString(strconv.Itoa(int(pkg.Epoch))) + sb.WriteByte(':') + } + + sb.WriteString(pkg.Version) + + if pkg.Release != 0 { + sb.WriteByte('-') + sb.WriteString(strconv.Itoa(pkg.Release)) + } + return sb.String() +} + +func genBadgeURL(pkgName, pkgVersion string) string { + v := url.Values{} + v.Set("label", pkgName) + v.Set("message", pkgVersion) + v.Set("logo", logoData) + v.Set("color", "blue") + u := &url.URL{Scheme: "https", Host: "img.shields.io", Path: "/static/v1", RawQuery: v.Encode()} + return u.String() +} diff --git a/cmd/lure-api-server/main.go b/cmd/lure-api-server/main.go index 80d1b91..88fb269 100644 --- a/cmd/lure-api-server/main.go +++ b/cmd/lure-api-server/main.go @@ -30,6 +30,7 @@ import ( "go.elara.ws/logger/log" "go.elara.ws/lure/internal/api" "go.elara.ws/lure/internal/repos" + "github.com/go-chi/chi/v5" ) func init() { @@ -60,16 +61,16 @@ func main() { sigCh := make(chan struct{}, 200) go repoPullWorker(ctx, sigCh) - - var handler http.Handler - - handler = api.NewAPIServer( + + apiServer := api.NewAPIServer( lureWebAPI{db: gdb}, twirp.WithServerPathPrefix(""), ) - handler = withAcceptLanguage(handler) - handler = allowAllCORSHandler(handler) - handler = handleWebhook(handler, sigCh) + + r := chi.NewRouter() + r.With(allowAllCORSHandler, withAcceptLanguage).Handle("/*", apiServer) + r.Post("/webhook", handleWebhook(sigCh)) + r.Get("/badge/{repo}/{pkg}", handleBadge(gdb)) ln, err := net.Listen("tcp", *addr) if err != nil { @@ -78,7 +79,7 @@ func main() { log.Info("Starting HTTP API server").Str("addr", ln.Addr().String()).Send() - err = http.Serve(ln, handler) + err = http.Serve(ln, r) if err != nil { log.Fatal("Error while running server").Err(err).Send() } diff --git a/cmd/lure-api-server/webhook.go b/cmd/lure-api-server/webhook.go index 1cd1862..bfc3cf8 100644 --- a/cmd/lure-api-server/webhook.go +++ b/cmd/lure-api-server/webhook.go @@ -33,30 +33,21 @@ import ( "go.elara.ws/lure/internal/repos" ) -func handleWebhook(next http.Handler, sigCh chan<- struct{}) http.Handler { +func handleWebhook(sigCh chan<- struct{}) http.HandlerFunc { 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{}{} + if req.Header.Get("X-GitHub-Event") != "push" { + http.Error(res, "Only push events are accepted by this bot", http.StatusBadRequest) return } - next.ServeHTTP(res, req) + err := verifySecure(req) + if err != nil { + http.Error(res, err.Error(), http.StatusForbidden) + return + } + + sigCh <- struct{}{} + return }) } diff --git a/go.mod b/go.mod index 30b7948..bf95a8a 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/charmbracelet/bubbles v0.14.0 github.com/charmbracelet/bubbletea v0.23.1 github.com/charmbracelet/lipgloss v0.6.0 + github.com/go-chi/chi/v5 v5.0.8 github.com/go-git/go-billy/v5 v5.3.1 github.com/go-git/go-git/v5 v5.4.2 github.com/goreleaser/nfpm/v2 v2.20.0 diff --git a/go.sum b/go.sum index 1045685..51e9eed 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3 github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=