diff --git a/go.mod b/go.mod index d2616b3..9bc6302 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.4.0 - github.com/hashicorp/go-memdb v1.3.4 github.com/labstack/echo/v4 v4.12.0 github.com/markbates/goth v1.80.0 github.com/pquerna/otp v1.4.0 @@ -71,8 +70,6 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/go-tpm v0.9.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.1 // indirect diff --git a/go.sum b/go.sum index 4486e60..57c72da 100644 --- a/go.sum +++ b/go.sum @@ -130,17 +130,6 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= -github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= -github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= -github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= -github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/internal/cli/main.go b/internal/cli/main.go index f4f6b85..f36f12b 100644 --- a/internal/cli/main.go +++ b/internal/cli/main.go @@ -8,7 +8,6 @@ import ( "github.com/thomiceli/opengist/internal/db" "github.com/thomiceli/opengist/internal/git" "github.com/thomiceli/opengist/internal/index" - "github.com/thomiceli/opengist/internal/memdb" "github.com/thomiceli/opengist/internal/ssh" "github.com/thomiceli/opengist/internal/web/server" "github.com/urfave/cli/v2" @@ -121,10 +120,6 @@ func Initialize(ctx *cli.Context) { log.Fatal().Err(err).Msg("Failed to initialize database") } - if err := memdb.Setup(); err != nil { - log.Fatal().Err(err).Msg("Failed to initialize in memory database") - } - if err := webauthn.Init(config.C.ExternalUrl); err != nil { log.Error().Err(err).Msg("Failed to initialize WebAuthn") } diff --git a/internal/db/gist.go b/internal/db/gist.go index af68b4d..1f75fde 100644 --- a/internal/db/gist.go +++ b/internal/db/gist.go @@ -1,6 +1,8 @@ package db import ( + "bytes" + "encoding/gob" "fmt" "os/exec" "path/filepath" @@ -567,6 +569,30 @@ func (gist *Gist) TopicsSlice() []string { return topics } +func (gist *Gist) SerialiseInitRepository() error { + var gobBuffer bytes.Buffer + encoder := gob.NewEncoder(&gobBuffer) + if err := encoder.Encode(gist); err != nil { + return fmt.Errorf("gob encoding error: %v", err) + } + + return git.SerialiseInitRepository(gist.User.Username, gobBuffer.Bytes()) +} + +func DeserialiseInitRepository(user string) (*Gist, error) { + data, err := git.DeserialiseInitRepository(user) + if err != nil { + return nil, err + } + + var gist Gist + decoder := gob.NewDecoder(bytes.NewReader(data)) + if err := decoder.Decode(&gist); err != nil { + return nil, fmt.Errorf("gob decoding error: %v", err) + } + return &gist, nil +} + func (gist *Gist) ToDTO() (*GistDTO, error) { files, err := gist.Files("HEAD", false) if err != nil { diff --git a/internal/git/commands.go b/internal/git/commands.go index 23a332c..f937cff 100644 --- a/internal/git/commands.go +++ b/internal/git/commands.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "context" + "encoding/base64" "fmt" "io" "net/url" @@ -38,6 +39,10 @@ func RepositoryPath(user string, gist string) string { return filepath.Join(config.GetHomeDir(), ReposDirectory, strings.ToLower(user), gist) } +func UserRepositoriesPath(user string) string { + return filepath.Join(config.GetHomeDir(), ReposDirectory, strings.ToLower(user)) +} + func RepositoryUrl(ctx echo.Context, user string, gist string) string { httpProtocol := "http" if ctx.Request().TLS != nil || ctx.Request().Header.Get("X-Forwarded-Proto") == "https" { @@ -560,6 +565,50 @@ func DeleteUserDirectory(user string) error { return os.RemoveAll(filepath.Join(config.GetHomeDir(), ReposDirectory, user)) } +func SerialiseInitRepository(user string, serialized []byte) error { + userRepositoryPath := UserRepositoriesPath(user) + initPath := filepath.Join(userRepositoryPath, "_init") + + f, err := os.OpenFile(initPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + + encodedData := base64.StdEncoding.EncodeToString(serialized) + _, err = f.Write(append([]byte(encodedData), '\n')) + return err +} + +func DeserialiseInitRepository(user string) ([]byte, error) { + initPath := filepath.Join(UserRepositoriesPath(user), "_init") + + content, err := os.ReadFile(initPath) + if err != nil { + return nil, err + } + + idx := bytes.Index(content, []byte{'\n'}) + if idx == -1 { + return base64.StdEncoding.DecodeString(string(content)) + } + + firstLine := content[:idx] + remaining := content[idx+1:] + + if len(remaining) == 0 { + if err := os.Remove(initPath); err != nil { + return nil, fmt.Errorf("failed to remove file: %v", err) + } + } else { + if err := os.WriteFile(initPath, remaining, 0644); err != nil { + return nil, fmt.Errorf("failed to write remaining content: %v", err) + } + } + + return base64.StdEncoding.DecodeString(string(firstLine)) +} + func createDotGitHookFile(repositoryPath string, hook string, content string) error { preReceiveDst, err := os.OpenFile(filepath.Join(repositoryPath, "hooks", hook), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0744) if err != nil { diff --git a/internal/memdb/memdb.go b/internal/memdb/memdb.go deleted file mode 100644 index 3b8a952..0000000 --- a/internal/memdb/memdb.go +++ /dev/null @@ -1,72 +0,0 @@ -package memdb - -import "github.com/hashicorp/go-memdb" -import ogdb "github.com/thomiceli/opengist/internal/db" - -var db *memdb.MemDB - -type GistInit struct { - UserID uint - Gist *ogdb.Gist -} - -func Setup() error { - var err error - schema := &memdb.DBSchema{ - Tables: map[string]*memdb.TableSchema{ - "gist_init": { - Name: "gist_init", - Indexes: map[string]*memdb.IndexSchema{ - "id": { - Name: "id", - Unique: true, - Indexer: &memdb.UintFieldIndex{Field: "UserID"}, - }, - }, - }, - }, - } - - db, err = memdb.NewMemDB(schema) - if err != nil { - return err - } - - return nil -} - -func InsertGistInit(userId uint, gist *ogdb.Gist) error { - txn := db.Txn(true) - if err := txn.Insert("gist_init", &GistInit{ - UserID: userId, - Gist: gist, - }); err != nil { - txn.Abort() - return err - } - - txn.Commit() - return nil -} - -func GetGistInitAndDelete(userId uint) (*GistInit, error) { - txn := db.Txn(true) - defer txn.Abort() - - raw, err := txn.First("gist_init", "id", userId) - if err != nil { - return nil, err - } - - if raw == nil { - return nil, nil - } - - gistInit := raw.(*GistInit) - if err := txn.Delete("gist_init", gistInit); err != nil { - return nil, err - } - - txn.Commit() - return gistInit, nil -} diff --git a/internal/web/handlers/git/http.go b/internal/web/handlers/git/http.go index 6e749a8..6f7aac8 100644 --- a/internal/web/handlers/git/http.go +++ b/internal/web/handlers/git/http.go @@ -23,7 +23,6 @@ import ( "github.com/thomiceli/opengist/internal/auth" "github.com/thomiceli/opengist/internal/db" "github.com/thomiceli/opengist/internal/git" - "github.com/thomiceli/opengist/internal/memdb" "gorm.io/gorm" ) @@ -157,18 +156,18 @@ func GitHttp(ctx *context.Context) error { return ctx.ErrorRes(500, "Cannot init repository in database", err) } - if err := memdb.InsertGistInit(user.ID, gist); err != nil { - return ctx.ErrorRes(500, "Cannot save the URL for the new Gist", err) + err = gist.SerialiseInitRepository() + if err != nil { + return ctx.ErrorRes(500, "Cannot serialise the repository", err) } ctx.SetData("gist", gist) } else { - gistFromMemdb, err := memdb.GetGistInitAndDelete(user.ID) + gist, err = db.DeserialiseInitRepository(user.Username) if err != nil { - return ctx.ErrorRes(500, "Cannot get the gist link from the in memory database", err) + return ctx.ErrorRes(500, "Cannot deserialise the repository", err) } - gist := gistFromMemdb.Gist ctx.SetData("gist", gist) ctx.SetData("repositoryPath", git.RepositoryPath(gist.User.Username, gist.Uuid)) } diff --git a/internal/web/test/server.go b/internal/web/test/server.go index ae225cb..b2d5875 100644 --- a/internal/web/test/server.go +++ b/internal/web/test/server.go @@ -21,7 +21,6 @@ import ( "github.com/thomiceli/opengist/internal/config" "github.com/thomiceli/opengist/internal/db" "github.com/thomiceli/opengist/internal/git" - "github.com/thomiceli/opengist/internal/memdb" "github.com/thomiceli/opengist/internal/web/server" ) @@ -183,9 +182,6 @@ func Setup(t *testing.T) *TestServer { log.Fatal().Err(err).Msg("Could not initialize database") } - err = memdb.Setup() - require.NoError(t, err, "Could not initialize in memory database") - // err = index.Open(filepath.Join(homePath, "testsindex", "opengist.index")) // require.NoError(t, err, "Could not open index")