fix(backend): use subdir collabs path

Ayman Bagabas created

Change summary

server/backend/file/file.go | 146 +++++++++-----------------------------
server/backend/file/repo.go |   4 
server/backend/noop/noop.go |  35 +--------
server/backend/server.go    |  13 ---
4 files changed, 41 insertions(+), 157 deletions(-)

Detailed changes

server/backend/file/file.go 🔗

@@ -26,7 +26,6 @@ import (
 	"io/fs"
 	"os"
 	"path/filepath"
-	"strconv"
 	"strings"
 
 	"github.com/charmbracelet/log"
@@ -41,13 +40,11 @@ const (
 	anonAccess   = "anon-access"
 	allowKeyless = "allow-keyless"
 	admins       = "admins"
-	serverHost   = "host"
-	serverName   = "name"
-	serverPort   = "port"
 	repos        = "repos"
 	collabs      = "collaborators"
 	description  = "description"
 	exportOk     = "git-daemon-export-ok"
+	private      = "private"
 	settings     = "settings"
 )
 
@@ -55,9 +52,6 @@ var (
 	logger = log.WithPrefix("backend.file")
 
 	defaults = map[string]string{
-		serverName:   "Soft Serve",
-		serverHost:   "localhost",
-		serverPort:   "23231",
 		anonAccess:   backend.ReadOnlyAccess.String(),
 		allowKeyless: "true",
 	}
@@ -94,7 +88,7 @@ func (fb *FileBackend) adminsPath() string {
 }
 
 func (fb *FileBackend) collabsPath(repo string) string {
-	return filepath.Join(fb.path, collabs, repo)
+	return filepath.Join(fb.path, collabs, repo, collabs)
 }
 
 func sanatizeRepo(repo string) string {
@@ -136,7 +130,8 @@ func NewFileBackend(path string) (*FileBackend, error) {
 			return nil, err
 		}
 	}
-	for _, file := range []string{admins, anonAccess, allowKeyless, serverHost, serverName, serverPort} {
+
+	for _, file := range []string{admins, anonAccess, allowKeyless} {
 		fp := filepath.Join(fb.settingsPath(), file)
 		_, err := os.Stat(fp)
 		if errors.Is(err, fs.ErrNotExist) {
@@ -216,28 +211,29 @@ func (fb *FileBackend) AddAdmin(pk gossh.PublicKey, memo string) error {
 // AddCollaborator adds a public key to the list of collaborators for the given repo.
 //
 // It implements backend.Backend.
-func (fb *FileBackend) AddCollaborator(pk gossh.PublicKey, memo string, name string) error {
+func (fb *FileBackend) AddCollaborator(pk gossh.PublicKey, memo string, repo string) error {
+	name := sanatizeRepo(repo)
+	repo = name + ".git"
 	// Check if repo exists
-	if !exists(filepath.Join(fb.reposPath(), sanatizeRepo(name)+".git")) {
-		return fmt.Errorf("repository %s does not exist", name)
+	if !exists(filepath.Join(fb.reposPath(), repo)) {
+		return fmt.Errorf("repository %s does not exist", repo)
 	}
 
 	// Skip if the key already exists.
-	if fb.IsCollaborator(pk, name) {
+	if fb.IsCollaborator(pk, repo) {
 		return fmt.Errorf("key already exists")
 	}
 
 	ak := backend.MarshalAuthorizedKey(pk)
-	name = sanatizeRepo(name)
-	if err := os.MkdirAll(filepath.Dir(fb.collabsPath(name)), 0755); err != nil {
+	if err := os.MkdirAll(filepath.Dir(fb.collabsPath(repo)), 0755); err != nil {
 		logger.Debug("failed to create collaborators directory",
-			"err", err, "path", filepath.Dir(fb.collabsPath(name)))
+			"err", err, "path", filepath.Dir(fb.collabsPath(repo)))
 		return err
 	}
 
-	f, err := os.OpenFile(fb.collabsPath(name), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
+	f, err := os.OpenFile(fb.collabsPath(repo), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
 	if err != nil {
-		logger.Debug("failed to open collaborators file", "err", err, "path", fb.collabsPath(name))
+		logger.Debug("failed to open collaborators file", "err", err, "path", fb.collabsPath(repo))
 		return err
 	}
 
@@ -273,8 +269,10 @@ func (fb *FileBackend) Admins() ([]string, error) {
 //
 // It implements backend.Backend.
 func (fb *FileBackend) Collaborators(repo string) ([]string, error) {
+	name := sanatizeRepo(repo)
+	repo = name + ".git"
 	// Check if repo exists
-	if !exists(filepath.Join(fb.reposPath(), sanatizeRepo(repo)+".git")) {
+	if !exists(filepath.Join(fb.reposPath(), repo)) {
 		return nil, fmt.Errorf("repository %s does not exist", repo)
 	}
 
@@ -297,7 +295,9 @@ func (fb *FileBackend) Collaborators(repo string) ([]string, error) {
 	return collabs, s.Err()
 }
 
-// RemoveAdmin implements backend.Backend
+// RemoveAdmin removes a public key from the list of server admins.
+//
+// It implements backend.Backend.
 func (fb *FileBackend) RemoveAdmin(pk gossh.PublicKey) error {
 	f, err := os.OpenFile(fb.adminsPath(), os.O_RDWR, 0644)
 	if err != nil {
@@ -350,8 +350,10 @@ func (fb *FileBackend) RemoveAdmin(pk gossh.PublicKey) error {
 //
 // It implements backend.Backend.
 func (fb *FileBackend) RemoveCollaborator(pk gossh.PublicKey, repo string) error {
+	name := sanatizeRepo(repo)
+	repo = name + ".git"
 	// Check if repo exists
-	if !exists(filepath.Join(fb.reposPath(), sanatizeRepo(repo)+".git")) {
+	if !exists(filepath.Join(fb.reposPath(), repo)) {
 		return fmt.Errorf("repository %s does not exist", repo)
 	}
 
@@ -489,16 +491,16 @@ func (fb *FileBackend) IsAdmin(pk gossh.PublicKey) bool {
 // given repo.
 //
 // It implements backend.Backend.
-func (fb *FileBackend) IsCollaborator(pk gossh.PublicKey, name string) bool {
-	name = sanatizeRepo(name)
-	_, err := os.Stat(fb.collabsPath(name))
+func (fb *FileBackend) IsCollaborator(pk gossh.PublicKey, repo string) bool {
+	repo = sanatizeRepo(repo) + ".git"
+	_, err := os.Stat(fb.collabsPath(repo))
 	if err != nil {
 		return false
 	}
 
-	f, err := os.Open(fb.collabsPath(name))
+	f, err := os.Open(fb.collabsPath(repo))
 	if err != nil {
-		logger.Debug("failed to open collaborators file", "err", err, "path", fb.collabsPath(name))
+		logger.Debug("failed to open collaborators file", "err", err, "path", fb.collabsPath(repo))
 		return false
 	}
 
@@ -526,50 +528,6 @@ func (fb *FileBackend) IsPrivate(repo string) bool {
 	return r.IsPrivate()
 }
 
-// ServerHost returns the server host.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) ServerHost() string {
-	line, err := readOneLine(filepath.Join(fb.settingsPath(), serverHost))
-	if err != nil {
-		logger.Debug("failed to read server-host file", "err", err)
-		return ""
-	}
-
-	return line
-}
-
-// ServerName returns the server name.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) ServerName() string {
-	line, err := readOneLine(filepath.Join(fb.settingsPath(), serverName))
-	if err != nil {
-		logger.Debug("failed to read server-name file", "err", err)
-		return ""
-	}
-
-	return line
-}
-
-// ServerPort returns the server port.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) ServerPort() string {
-	line, err := readOneLine(filepath.Join(fb.settingsPath(), serverPort))
-	if err != nil {
-		logger.Debug("failed to read server-port file", "err", err)
-		return ""
-	}
-
-	if _, err := strconv.Atoi(line); err != nil {
-		logger.Debug("failed to parse server-port file", "err", err)
-		return ""
-	}
-
-	return line
-}
-
 // SetAllowKeyless sets whether or not to allow keyless access.
 //
 // It implements backend.Backend.
@@ -621,6 +579,12 @@ func (fb *FileBackend) SetPrivate(repo string, priv bool) error {
 	daemonExport := filepath.Join(fb.reposPath(), repo, exportOk)
 	if priv {
 		_ = os.Remove(daemonExport)
+		f, err := os.Create(filepath.Join(fb.reposPath(), repo, private))
+		if err != nil {
+			return fmt.Errorf("failed to create private file: %w", err)
+		}
+
+		_ = f.Close() //nolint:errcheck
 	} else {
 		// Create git-daemon-export-ok file if repo is public.
 		f, err := os.Create(daemonExport)
@@ -633,48 +597,6 @@ func (fb *FileBackend) SetPrivate(repo string, priv bool) error {
 	return nil
 }
 
-// SetServerHost sets the server host.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) SetServerHost(host string) error {
-	f, err := os.Create(filepath.Join(fb.settingsPath(), serverHost))
-	if err != nil {
-		return fmt.Errorf("failed to create server-host file: %w", err)
-	}
-
-	defer f.Close() //nolint:errcheck
-	_, err = fmt.Fprintln(f, host)
-	return err
-}
-
-// SetServerName sets the server name.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) SetServerName(name string) error {
-	f, err := os.Create(filepath.Join(fb.settingsPath(), serverName))
-	if err != nil {
-		return fmt.Errorf("failed to create server-name file: %w", err)
-	}
-
-	defer f.Close() //nolint:errcheck
-	_, err = fmt.Fprintln(f, name)
-	return err
-}
-
-// SetServerPort sets the server port.
-//
-// It implements backend.Backend.
-func (fb *FileBackend) SetServerPort(port string) error {
-	f, err := os.Create(filepath.Join(fb.settingsPath(), serverPort))
-	if err != nil {
-		return fmt.Errorf("failed to create server-port file: %w", err)
-	}
-
-	defer f.Close() //nolint:errcheck
-	_, err = fmt.Fprintln(f, port)
-	return err
-}
-
 // CreateRepository creates a new repository.
 //
 // Created repositories are always bare.

server/backend/file/repo.go 🔗

@@ -45,8 +45,8 @@ func (r *Repo) Description() string {
 //
 // It implements backend.Repository.
 func (r *Repo) IsPrivate() bool {
-	_, err := os.Stat(filepath.Join(r.path, exportOk))
-	return err != nil
+	_, err := os.Stat(filepath.Join(r.path, private))
+	return err == nil
 }
 
 // Open returns the underlying git.Repository.

server/backend/noop/noop.go 🔗

@@ -21,6 +21,11 @@ type Noop struct {
 	Port string
 }
 
+// RepositoryStorePath implements backend.Backend
+func (*Noop) RepositoryStorePath() string {
+	return ""
+}
+
 // Admins implements backend.Backend
 func (*Noop) Admins() ([]string, error) {
 	return nil, nil
@@ -122,21 +127,6 @@ func (*Noop) Repository(repo string) (backend.Repository, error) {
 	return nil, ErrNotImpl
 }
 
-// ServerHost implements backend.Backend
-func (*Noop) ServerHost() string {
-	return "localhost"
-}
-
-// ServerName implements backend.Backend
-func (*Noop) ServerName() string {
-	return "Soft Serve"
-}
-
-// ServerPort implements backend.Backend
-func (n *Noop) ServerPort() string {
-	return n.Port
-}
-
 // SetAllowKeyless implements backend.Backend
 func (*Noop) SetAllowKeyless(allow bool) error {
 	return ErrNotImpl
@@ -156,18 +146,3 @@ func (*Noop) SetDescription(repo string, desc string) error {
 func (*Noop) SetPrivate(repo string, priv bool) error {
 	return ErrNotImpl
 }
-
-// SetServerHost implements backend.Backend
-func (*Noop) SetServerHost(host string) error {
-	return ErrNotImpl
-}
-
-// SetServerName implements backend.Backend
-func (*Noop) SetServerName(name string) error {
-	return ErrNotImpl
-}
-
-// SetServerPort implements backend.Backend
-func (*Noop) SetServerPort(port string) error {
-	return ErrNotImpl
-}

server/backend/server.go 🔗

@@ -2,19 +2,6 @@ package backend
 
 // ServerBackend is an interface that handles server configuration.
 type ServerBackend interface {
-	// ServerName returns the server's name.
-	ServerName() string
-	// SetServerName sets the server's name.
-	SetServerName(name string) error
-	// ServerHost returns the server's host.
-	ServerHost() string
-	// SetServerHost sets the server's host.
-	SetServerHost(host string) error
-	// ServerPort returns the server's port.
-	ServerPort() string
-	// SetServerPort sets the server's port.
-	SetServerPort(port string) error
-
 	// AnonAccess returns the access level for anonymous users.
 	AnonAccess() AccessLevel
 	// SetAnonAccess sets the access level for anonymous users.