Create gists from git http server endpoint (#95)

This commit is contained in:
Thomas Miceli
2023-09-09 19:39:57 +02:00
committed by GitHub
parent 977fc9db28
commit 46dea89b41
10 changed files with 276 additions and 25 deletions

View File

@ -104,6 +104,14 @@ func gistSoftInit(next echo.HandlerFunc) echo.HandlerFunc {
}
}
// gistNewPushInit has the same behavior as gistSoftInit but create a new gist empty instead
func gistNewPushSoftInit(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
setData(c, "gist", new(db.Gist))
return next(c)
}
}
func allGists(ctx echo.Context) error {
var err error
var urlPage string
@ -428,11 +436,6 @@ func toggleVisibility(ctx echo.Context) error {
func deleteGist(ctx echo.Context) error {
var gist = getData(ctx, "gist").(*db.Gist)
err := gist.DeleteRepository()
if err != nil {
return errorRes(500, "Error deleting the repository", err)
}
if err := gist.Delete(); err != nil {
return errorRes(500, "Error deleting this gist", err)
}

View File

@ -4,11 +4,15 @@ import (
"bytes"
"compress/gzip"
"encoding/base64"
"errors"
"fmt"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/rs/zerolog/log"
"github.com/thomiceli/opengist/internal/db"
"github.com/thomiceli/opengist/internal/git"
"github.com/thomiceli/opengist/internal/memdb"
"gorm.io/gorm"
"net/http"
"os"
"os/exec"
@ -47,8 +51,9 @@ func gitHttp(ctx echo.Context) error {
gist := getData(ctx, "gist").(*db.Gist)
isPushNew := strings.HasPrefix(ctx.Request().URL.Path, "/push/info/refs")
isPushReceive := strings.HasPrefix(ctx.Request().URL.Path, "/push/git-receive-pack")
isInfoRefs := strings.HasSuffix(route.gitUrl, "/info/refs$")
isPull := ctx.QueryParam("service") == "git-upload-pack" ||
strings.HasSuffix(ctx.Request().URL.Path, "git-upload-pack") ||
ctx.Request().Method == "GET" && !isInfoRefs
@ -61,7 +66,7 @@ func gitHttp(ctx echo.Context) error {
}
}
ctx.Set("repositoryPath", repositoryPath)
setData(ctx, "repositoryPath", repositoryPath)
// Shows basic auth if :
// - user wants to push the gist
@ -87,16 +92,70 @@ func gitHttp(ctx echo.Context) error {
return basicAuth(ctx)
}
if gist.ID == 0 {
return plainText(ctx, 404, "Check your credentials or make sure you have access to the Gist")
}
if ok, err := argon2id.verify(authPassword, gist.User.Password); !ok || gist.User.Username != authUsername {
if err != nil {
return errorRes(500, "Cannot verify password", err)
if !isPushNew && !isPushReceive {
if gist.ID == 0 {
return plainText(ctx, 404, "Check your credentials or make sure you have access to the Gist")
}
if ok, err := argon2id.verify(authPassword, gist.User.Password); !ok || gist.User.Username != authUsername {
if err != nil {
return errorRes(500, "Cannot verify password", err)
}
log.Warn().Msg("Invalid HTTP authentication attempt from " + ctx.RealIP())
return plainText(ctx, 404, "Check your credentials or make sure you have access to the Gist")
}
} else {
var user *db.User
if user, err = db.GetUserByUsername(authUsername); err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return errorRes(500, "Cannot get user", err)
}
log.Warn().Msg("Invalid HTTP authentication attempt from " + ctx.RealIP())
return errorRes(401, "Invalid credentials", nil)
}
if ok, err := argon2id.verify(authPassword, user.Password); !ok {
if err != nil {
return errorRes(500, "Cannot check for password", err)
}
log.Warn().Msg("Invalid HTTP authentication attempt from " + ctx.RealIP())
return errorRes(401, "Invalid credentials", nil)
}
if isPushNew {
gist = new(db.Gist)
gist.UserID = user.ID
gist.User = *user
uuidGist, err := uuid.NewRandom()
if err != nil {
return errorRes(500, "Error creating an UUID", err)
}
gist.Uuid = strings.Replace(uuidGist.String(), "-", "", -1)
gist.Title = "gist:" + gist.Uuid
if err = gist.InitRepositoryViaNewPush(ctx); err != nil {
return errorRes(500, "Cannot init repository in the file system", err)
}
if err = gist.Create(); err != nil {
return errorRes(500, "Cannot init repository in database", err)
}
if err := memdb.InsertGistPush(user.ID, gist); err != nil {
return errorRes(500, "Cannot save the URL for the new Gist", err)
}
setData(ctx, "gist", gist)
} else {
gistFromMemdb, err := memdb.GetGistPushAndDelete(user.ID)
if err != nil {
return errorRes(500, "Cannot get the gist link from the in memory database", err)
}
gist := gistFromMemdb.Gist
setData(ctx, "gist", gist)
setData(ctx, "repositoryPath", git.RepositoryPath(gist.User.Username, gist.Uuid))
}
log.Warn().Msg("Invalid HTTP authentication attempt from " + ctx.RealIP())
return plainText(ctx, 404, "Check your credentials or make sure you have access to the Gist")
}
return route.handler(ctx)
@ -132,7 +191,7 @@ func pack(ctx echo.Context, serviceType string) error {
}
}
repositoryPath := ctx.Get("repositoryPath").(string)
repositoryPath := getData(ctx, "repositoryPath").(string)
var stderr bytes.Buffer
cmd := exec.Command("git", serviceType, "--stateless-rpc", repositoryPath)
@ -147,6 +206,15 @@ func pack(ctx echo.Context, serviceType string) error {
// updatedAt is updated only if serviceType is receive-pack
if serviceType == "receive-pack" {
gist := getData(ctx, "gist").(*db.Gist)
if hasNoCommits, err := git.HasNoCommits(gist.User.Username, gist.Uuid); err != nil {
return err
} else if hasNoCommits {
if err = gist.Delete(); err != nil {
return err
}
}
_ = gist.SetLastActiveNow()
_ = gist.UpdatePreviewAndCount()
}
@ -241,7 +309,7 @@ func basicAuthDecode(encoded string) (string, string, error) {
func sendFile(ctx echo.Context, contentType string) error {
gitFile := "/" + strings.Join(strings.Split(ctx.Request().URL.Path, "/")[3:], "/")
gitFile = path.Join(ctx.Get("repositoryPath").(string), gitFile)
gitFile = path.Join(getData(ctx, "repositoryPath").(string), gitFile)
fi, err := os.Stat(gitFile)
if os.IsNotExist(err) {
return errorRes(404, "File not found", nil)

View File

@ -212,6 +212,10 @@ func Start() {
g2.PUT("/set-config", adminSetConfig)
}
if config.C.HttpGit {
e.Any("/push/*", gitHttp, gistNewPushSoftInit)
}
g1.GET("/all", allGists, checkRequireLogin)
g1.GET("/search", allGists, checkRequireLogin)
g1.GET("/:user", allGists, checkRequireLogin)

View File

@ -167,7 +167,7 @@ func validateReservedKeywords(fl validator.FieldLevel) bool {
name := fl.Field().String()
restrictedNames := map[string]struct{}{}
for _, restrictedName := range []string{"assets", "register", "login", "logout", "settings", "admin-panel", "all", "search"} {
for _, restrictedName := range []string{"assets", "register", "login", "logout", "settings", "admin-panel", "all", "search", "push"} {
restrictedNames[restrictedName] = struct{}{}
}