From 05eb4845425f81167619e3acb5d7450b228369f3 Mon Sep 17 00:00:00 2001 From: Peter Sanchez Date: Wed, 27 Dec 2023 07:49:58 -0600 Subject: [PATCH] Base middleware to check for repo fetch --- cmd/gohome/main.go | 7 +----- config.example.ini | 3 --- middleware.go | 54 ++++++++++++++++++++++++++++++++++++++++++ routes.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 9 deletions(-) diff --git a/cmd/gohome/main.go b/cmd/gohome/main.go index 49071d8..009f3ca 100644 --- a/cmd/gohome/main.go +++ b/cmd/gohome/main.go @@ -15,7 +15,6 @@ import ( "github.com/alexedwards/scs/v2" "github.com/labstack/echo/v4" "netlandish.com/x/gobwebs/config" - "netlandish.com/x/gobwebs/crypto" "netlandish.com/x/gobwebs/database" "netlandish.com/x/gobwebs/server" "petersanchez.com/x/migrate" @@ -37,10 +36,6 @@ func run() error { return err } - entropy, ok := config.File.Get("access", "entropy") - if !ok { - return fmt.Errorf("No access entropy set. Required value") - } root, _ := config.File.Get("gohome", "root") if root != "" && !strings.HasPrefix(root, "/") { root = fmt.Sprintf("/%s", root) @@ -77,7 +72,7 @@ func run() error { DefaultMiddlewareWithConfig(mwConf). WithMiddleware( database.Middleware(db), - crypto.Middleware(entropy), + gohome.Middleware(root), ) svc := e.Group(root) diff --git a/config.example.ini b/config.example.ini index 435b4a5..4fca7be 100644 --- a/config.example.ini +++ b/config.example.ini @@ -52,9 +52,6 @@ connection-string = gohome.db # Defaults to: ./ root-directory=./ -[access] -entropy=Entropy value - [gohome] # Set to the value of the root URL path. Ie, if the repo URL is # yourdomain.com/x/repo-name then the root value is 'x'. leave blank diff --git a/middleware.go b/middleware.go index 2d758f4..0a78076 100644 --- a/middleware.go +++ b/middleware.go @@ -1,11 +1,65 @@ package gohome import ( + "context" + "fmt" "net/http" + "strings" "github.com/labstack/echo/v4" ) +var rootCtxKey = &contextKey{"root"} + +type contextKey struct { + name string +} + +// Context adds user object to context for immediate use +func Context(ctx context.Context, root string) context.Context { + return context.WithValue(ctx, rootCtxKey, root) +} + +// ForContext pulls user value for context +func ForContext(ctx context.Context) string { + root, ok := ctx.Value(rootCtxKey).(string) + if !ok { + return "" + } + return root +} + +// Middleware adds root path to the context +func Middleware(root string) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + c.SetRequest(c.Request().WithContext(Context(c.Request().Context(), root))) + return next(c) + } + } +} + +// RepoMiddleware will check the request path and see if it matches a repo. +func RepoMiddleware(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + path := c.Request().URL.Path + if !strings.HasPrefix(path, "/") { + path = fmt.Sprintf("/%s", path) + } + adminPath := c.Echo().Reverse("home:admin_home") + if strings.HasPrefix(path, adminPath) { + // Using the --admin-- url routes. Don't bother doing any + // further checks. + return next(c) + } + + root := ForContext(c.Request().Context()) + path = strings.TrimPrefix(path, root) + path = strings.TrimPrefix(path, "/") + return GetRepoFromPath(c, path) + } +} + // AuthRequired will ensure that the user has entered the correct password func AuthRequired(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { diff --git a/routes.go b/routes.go index 0b6dd9c..baeac03 100644 --- a/routes.go +++ b/routes.go @@ -3,11 +3,15 @@ package gohome import ( "fmt" "net/http" + "net/url" "strconv" + "strings" + sq "github.com/Masterminds/squirrel" "github.com/alexedwards/argon2id" "github.com/labstack/echo/v4" "netlandish.com/x/gobwebs" + "netlandish.com/x/gobwebs/database" "netlandish.com/x/gobwebs/messages" "netlandish.com/x/gobwebs/server" "netlandish.com/x/gobwebs/validate" @@ -218,6 +222,60 @@ func (s *Service) RepoAddEdit(c echo.Context) error { return gctx.Render(http.StatusOK, "add_edit.html", gmap) } +// GetRepo will check the path for an active repo and return it +func GetRepoFromPath(c echo.Context, path string) error { + parts := strings.Split(path, "/") + if len(parts) > 3 { + // TODO re-think this? + parts = parts[:3] + } + + var ( + repo *Repo + rname string + ) + for i := 0; i < 3; i++ { + // XXX Is this even needed? Should it just be the first value (parts[0])? + rname = strings.Join(parts[:i+1], "/") + opts := &database.FilterOptions{ + Filter: sq.And{ + sq.Eq{"reponame": strings.ToLower(rname)}, + sq.Eq{"is_active": true}, + }, + Limit: 1, + } + repos, err := GetRepos(c.Request().Context(), opts) + if err != nil { + return err + } + if len(repos) == 0 { + continue + } + repo = repos[0] + break + } + + if repo == nil { + return echo.NotFoundHandler(c) + } + + gctx := c.(*server.Context) + if c.QueryParams().Get("go-get") == "1" { + root := ForContext(c.Request().Context()) + fpath, err := url.JoinPath(root, rname) + if err != nil { + return err + } + rdomain := fmt.Sprintf("%s%s", gctx.Server.Config.Domain, fpath) + return c.HTML(http.StatusOK, + fmt.Sprintf(``, + rdomain, repo.RepoType, repo.RepoURL), + ) + } + gmap := gobwebs.Map{"repo": repo} + return gctx.Render(http.StatusOK, "repo_detail.html", gmap) +} + // RouteName ... func (s *Service) RouteName(value string) string { return fmt.Sprintf("%s:%s", s.name, value) -- 2.45.2