From 516f568a27ffb668967b03a34d6e4244366093e5 Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Tue, 28 Jan 2025 15:35:24 +0200 Subject: [PATCH] keyfetch: add keyfetch and internal api --- cmd/keyfetch/format.go | 15 +++++++++ cmd/keyfetch/format_test.go | 45 +++++++++++++++++++++++++++ cmd/keyfetch/main.go | 35 +++++++++++++++++++++ cmd/legit/main.go | 18 +++++++++-- cmd/repoguard/main.go | 12 +++++-- config.yaml | 2 ++ config/config.go | 3 ++ db/pubkeys.go | 29 +++++++++++++++-- routes/handler.go | 7 +---- routes/internal.go | 62 +++++++++++++++++++++++++++++++++++++ routes/routes.go | 11 ++++++- 11 files changed, 225 insertions(+), 14 deletions(-) create mode 100644 cmd/keyfetch/format.go create mode 100644 cmd/keyfetch/format_test.go create mode 100644 cmd/keyfetch/main.go create mode 100644 routes/internal.go diff --git a/cmd/keyfetch/format.go b/cmd/keyfetch/format.go new file mode 100644 index 0000000..ea80e01 --- /dev/null +++ b/cmd/keyfetch/format.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" +) + +func formatKeyData(repoguardPath string, data map[string]string) string { + var result string + for user, key := range data { + result += fmt.Sprintf( + `command="%s -base-dir /home/git -user %s -log-path /home/git/log ",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s`+"\n", + repoguardPath, user, key) + } + return result +} diff --git a/cmd/keyfetch/format_test.go b/cmd/keyfetch/format_test.go new file mode 100644 index 0000000..4d5b9d1 --- /dev/null +++ b/cmd/keyfetch/format_test.go @@ -0,0 +1,45 @@ +package main + +import "testing" + +func TestFormatKeyData(t *testing.T) { + tests := []struct { + name string + repoguardPath string + data map[string]string + want string + }{ + { + name: "single user", + repoguardPath: "/usr/bin/repoguard", + data: map[string]string{ + "user1": "ssh-rsa AAAA...", + }, + want: `command="/usr/bin/repoguard -base-dir /home/git -user user1 -log-path /home/git/log ",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAA...` + "\n", + }, + { + name: "multiple users", + repoguardPath: "/usr/bin/repoguard", + data: map[string]string{ + "user1": "ssh-rsa AAAA...", + "user2": "ssh-rsa BBBB...", + }, + want: `command="/usr/bin/repoguard -base-dir /home/git -user user1 -log-path /home/git/log ",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAA...` + "\n" + + `command="/usr/bin/repoguard -base-dir /home/git -user user2 -log-path /home/git/log ",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa BBBB...` + "\n", + }, + { + name: "empty data", + repoguardPath: "/usr/bin/repoguard", + data: map[string]string{}, + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := formatKeyData(tt.repoguardPath, tt.data); got != tt.want { + t.Errorf("formatKeyData() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/keyfetch/main.go b/cmd/keyfetch/main.go new file mode 100644 index 0000000..75fe096 --- /dev/null +++ b/cmd/keyfetch/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "log" + "net/http" +) + +func main() { + endpoint := flag.String("internal-api", "http://localhost:5444", "Internal API endpoint") + repoguardPath := flag.String("repoguard-path", "/home/git/repoguard", "Path to the repoguard binary") + flag.Parse() + + resp, err := http.Get(*endpoint + "/internal/allkeys") + if err != nil { + log.Fatalf("error fetching keys: %v", err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatalf("error reading response body: %v", err) + } + + var data map[string]string + err = json.Unmarshal(body, &data) + if err != nil { + log.Fatalf("error unmarshalling response body: %v", err) + } + + fmt.Print(formatKeyData(*repoguardPath, data)) +} diff --git a/cmd/legit/main.go b/cmd/legit/main.go index 7bdef06..6eb0ad1 100644 --- a/cmd/legit/main.go +++ b/cmd/legit/main.go @@ -9,6 +9,7 @@ import ( "os" "github.com/icyphox/bild/config" + "github.com/icyphox/bild/db" "github.com/icyphox/bild/routes" ) @@ -23,13 +24,24 @@ func main() { if err != nil { log.Fatal(err) } + db, err := db.Setup(c.Server.DBPath) + if err != nil { + log.Fatalf("failed to setup db: %s", err) + } - mux, err := routes.Setup(c) + mux, err := routes.Setup(c, db) if err != nil { log.Fatal(err) } + internalMux := routes.SetupInternal(c, db) + addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) - log.Println("starting server on", addr) - log.Fatal(http.ListenAndServe(addr, mux)) + internalAddr := fmt.Sprintf("%s:%d", c.Server.InternalHost, c.Server.InternalPort) + + log.Println("starting main server on", addr) + go http.ListenAndServe(addr, mux) + + log.Println("starting internal server on", internalAddr) + log.Fatal(http.ListenAndServe(internalAddr, internalMux)) } diff --git a/cmd/repoguard/main.go b/cmd/repoguard/main.go index 2d32591..2eafdf7 100644 --- a/cmd/repoguard/main.go +++ b/cmd/repoguard/main.go @@ -143,6 +143,14 @@ func cleanup() { } func isAllowedUser(user, repoPath string) bool { - pathUser := strings.Split(repoPath, "/")[0] - return pathUser == user + fullPath := filepath.Join(*baseDirFlag, repoPath) + didPath := filepath.Join(fullPath, "did") + + didBytes, err := os.ReadFile(didPath) + if err != nil { + return false + } + + allowedUser := strings.TrimSpace(string(didBytes)) + return allowedUser == user } diff --git a/config.yaml b/config.yaml index 8ba1c30..0322f66 100644 --- a/config.yaml +++ b/config.yaml @@ -19,3 +19,5 @@ server: host: 0.0.0.0 port: 5555 dbpath: bild.db + internalHost: 127.0.0.1 + internalPort: 5444 diff --git a/config/config.go b/config/config.go index 7ff466f..c682321 100644 --- a/config/config.go +++ b/config/config.go @@ -30,6 +30,9 @@ type Config struct { Host string `yaml:"host"` Port int `yaml:"port"` DBPath string `yaml:"dbpath"` + + InternalHost string `yaml:"internalHost,omitempty"` + InternalPort int `yaml:"internalPort,omitempty"` } `yaml:"server"` } diff --git a/db/pubkeys.go b/db/pubkeys.go index a4926e2..9817fc0 100644 --- a/db/pubkeys.go +++ b/db/pubkeys.go @@ -17,13 +17,38 @@ func (d *DB) RemovePublicKey(did string) error { type PublicKey struct { Key string Name string + DID string Created time.Time } +func (d *DB) GetAllPublicKeys() ([]PublicKey, error) { + var keys []PublicKey + + rows, err := d.db.Query(`select key, name, did, created from public_keys`) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var publicKey PublicKey + if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.DID, &publicKey.Created); err != nil { + return nil, err + } + keys = append(keys, publicKey) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return keys, nil +} + func (d *DB) GetPublicKeys(did string) ([]PublicKey, error) { var keys []PublicKey - rows, err := d.db.Query(`select key, name, created from public_keys where did = ?`, did) + rows, err := d.db.Query(`select did, key, name, created from public_keys where did = ?`, did) if err != nil { return nil, err } @@ -31,7 +56,7 @@ func (d *DB) GetPublicKeys(did string) ([]PublicKey, error) { for rows.Next() { var publicKey PublicKey - if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.Created); err != nil { + if err := rows.Scan(&publicKey.DID, &publicKey.Key, &publicKey.Name, &publicKey.Created); err != nil { return nil, err } keys = append(keys, publicKey) diff --git a/routes/handler.go b/routes/handler.go index a3002e7..483ba2f 100644 --- a/routes/handler.go +++ b/routes/handler.go @@ -37,7 +37,7 @@ func (h *Handle) Multiplex(w http.ResponseWriter, r *http.Request) { } } -func Setup(c *config.Config) (http.Handler, error) { +func Setup(c *config.Config, db *db.DB) (http.Handler, error) { r := chi.NewRouter() s := sessions.NewCookieStore([]byte("TODO_CHANGE_ME")) t, err := tmpl.Load(c.Dirs.Templates) @@ -47,11 +47,6 @@ func Setup(c *config.Config) (http.Handler, error) { auth := auth.NewAuth(s) - db, err := db.Setup(c.Server.DBPath) - if err != nil { - return nil, fmt.Errorf("failed to setup db: %w", err) - } - h := Handle{ c: c, t: t, diff --git a/routes/internal.go b/routes/internal.go new file mode 100644 index 0000000..960f2d8 --- /dev/null +++ b/routes/internal.go @@ -0,0 +1,62 @@ +package routes + +import ( + "encoding/json" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/icyphox/bild/config" + "github.com/icyphox/bild/db" +) + +type InternalHandle struct { + c *config.Config + db *db.DB +} + +func SetupInternal(c *config.Config, db *db.DB) http.Handler { + ih := &InternalHandle{ + c: c, + db: db, + } + + r := chi.NewRouter() + r.Route("/internal/allkeys", func(r chi.Router) { + r.Get("/", ih.AllKeys) + }) + + return r +} + +func (h *InternalHandle) returnJSON(w http.ResponseWriter, data interface{}) error { + w.Header().Set("Content-Type", "application/json") + res, err := json.Marshal(data) + if err != nil { + return err + } + _, err = w.Write(res) + return err +} + +func (h *InternalHandle) returnErr(w http.ResponseWriter, err error) error { + w.WriteHeader(http.StatusInternalServerError) + return h.returnJSON(w, map[string]string{ + "error": err.Error(), + }) +} + +func (h *InternalHandle) AllKeys(w http.ResponseWriter, r *http.Request) { + keys, err := h.db.GetAllPublicKeys() + if err != nil { + h.returnErr(w, err) + return + } + keyMap := map[string]string{} + for _, key := range keys { + keyMap[key.DID] = key.Key + } + if err := h.returnJSON(w, keyMap); err != nil { + h.returnErr(w, err) + return + } +} diff --git a/routes/routes.go b/routes/routes.go index 8968e82..ce11102 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -524,7 +524,16 @@ func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) { name := r.FormValue("name") description := r.FormValue("description") - err := git.InitBare(filepath.Join(h.c.Repo.ScanPath, handle, name)) + repoPath := filepath.Join(h.c.Repo.ScanPath, handle, name) + err := git.InitBare(repoPath) + if err != nil { + h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") + return + } + + // For use by repoguard + didPath := filepath.Join(repoPath, "did") + err = os.WriteFile(didPath, []byte(did), 0644) if err != nil { h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") return -- 2.51.2