mirror of
https://github.com/thomiceli/opengist.git
synced 2025-06-13 05:47:12 +02:00
Create gists from git http server endpoint (#95)
This commit is contained in:
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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{}{}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user