~petersanchez/gohome

05eb4845425f81167619e3acb5d7450b228369f3 — Peter Sanchez 10 months ago 1cdc4ff
Base middleware to check for repo fetch
4 files changed, 113 insertions(+), 9 deletions(-)

M cmd/gohome/main.go
M config.example.ini
M middleware.go
M routes.go
M cmd/gohome/main.go => cmd/gohome/main.go +1 -6
@@ 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)

M config.example.ini => config.example.ini +0 -3
@@ 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

M middleware.go => middleware.go +54 -0
@@ 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 {

M routes.go => routes.go +58 -0
@@ 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(`<meta name="go-import" content="%s %s %s" />`,
				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)