package main
import (
"flag"
"fmt"
"log"
"net/http"
"os/user"
"path/filepath"
"strings"
"git-browser/internal/repository"
"git-browser/internal/web"
)
func main() {
sshUser := flag.String("ssh-user", "git", "SSH user allowed to access repositories")
root := flag.String("root", "repos", "repository root relative to the SSH user's home directory")
listen := flag.String("listen", ":8080", "HTTP listen address")
flag.Parse()
resolvedRoot, cloneRoot, err := resolveRoot(*sshUser, *root)
if err != nil {
log.Fatalf("resolve repository root: %v", err)
}
store, err := repository.Discover(resolvedRoot)
if err != nil {
log.Fatalf("discover repositories: %v", err)
}
server, err := web.NewServer(store, web.Config{
SSHUser: *sshUser,
CloneRoot: cloneRoot,
})
if err != nil {
log.Fatalf("create server: %v", err)
}
log.Printf("serving %s on %s", store.Root(), *listen)
if err := http.ListenAndServe(*listen, server.Handler()); err != nil {
log.Fatal(err)
}
}
func resolveRoot(userName, root string) (string, string, error) {
account, err := user.Lookup(userName)
if err != nil {
return "", "", err
}
cleaned := filepath.Clean(root)
if root == "" || cleaned == "." {
return account.HomeDir, "", nil
}
if filepath.IsAbs(cleaned) || cleaned == ".." || strings.HasPrefix(cleaned, ".."+string(filepath.Separator)) {
return "", "", fmt.Errorf("root must stay within %s's home directory", userName)
}
return filepath.Join(account.HomeDir, cleaned), filepath.ToSlash(cleaned), nil
}