this repo has no description

keyfetch: add keyfetch and internal api

Changed files
+225 -14
cmd
keyfetch
legit
repoguard
config
db
routes
+15
cmd/keyfetch/format.go
··· 1 + package main 2 + 3 + import ( 4 + "fmt" 5 + ) 6 + 7 + func formatKeyData(repoguardPath string, data map[string]string) string { 8 + var result string 9 + for user, key := range data { 10 + result += fmt.Sprintf( 11 + `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", 12 + repoguardPath, user, key) 13 + } 14 + return result 15 + }
+45
cmd/keyfetch/format_test.go
··· 1 + package main 2 + 3 + import "testing" 4 + 5 + func TestFormatKeyData(t *testing.T) { 6 + tests := []struct { 7 + name string 8 + repoguardPath string 9 + data map[string]string 10 + want string 11 + }{ 12 + { 13 + name: "single user", 14 + repoguardPath: "/usr/bin/repoguard", 15 + data: map[string]string{ 16 + "user1": "ssh-rsa AAAA...", 17 + }, 18 + 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", 19 + }, 20 + { 21 + name: "multiple users", 22 + repoguardPath: "/usr/bin/repoguard", 23 + data: map[string]string{ 24 + "user1": "ssh-rsa AAAA...", 25 + "user2": "ssh-rsa BBBB...", 26 + }, 27 + 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" + 28 + `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", 29 + }, 30 + { 31 + name: "empty data", 32 + repoguardPath: "/usr/bin/repoguard", 33 + data: map[string]string{}, 34 + want: "", 35 + }, 36 + } 37 + 38 + for _, tt := range tests { 39 + t.Run(tt.name, func(t *testing.T) { 40 + if got := formatKeyData(tt.repoguardPath, tt.data); got != tt.want { 41 + t.Errorf("formatKeyData() = %v, want %v", got, tt.want) 42 + } 43 + }) 44 + } 45 + }
+35
cmd/keyfetch/main.go
··· 1 + package main 2 + 3 + import ( 4 + "encoding/json" 5 + "flag" 6 + "fmt" 7 + "io" 8 + "log" 9 + "net/http" 10 + ) 11 + 12 + func main() { 13 + endpoint := flag.String("internal-api", "http://localhost:5444", "Internal API endpoint") 14 + repoguardPath := flag.String("repoguard-path", "/home/git/repoguard", "Path to the repoguard binary") 15 + flag.Parse() 16 + 17 + resp, err := http.Get(*endpoint + "/internal/allkeys") 18 + if err != nil { 19 + log.Fatalf("error fetching keys: %v", err) 20 + } 21 + defer resp.Body.Close() 22 + 23 + body, err := io.ReadAll(resp.Body) 24 + if err != nil { 25 + log.Fatalf("error reading response body: %v", err) 26 + } 27 + 28 + var data map[string]string 29 + err = json.Unmarshal(body, &data) 30 + if err != nil { 31 + log.Fatalf("error unmarshalling response body: %v", err) 32 + } 33 + 34 + fmt.Print(formatKeyData(*repoguardPath, data)) 35 + }
+15 -3
cmd/legit/main.go
··· 9 9 "os" 10 10 11 11 "github.com/icyphox/bild/config" 12 + "github.com/icyphox/bild/db" 12 13 "github.com/icyphox/bild/routes" 13 14 ) 14 15 ··· 23 24 if err != nil { 24 25 log.Fatal(err) 25 26 } 27 + db, err := db.Setup(c.Server.DBPath) 28 + if err != nil { 29 + log.Fatalf("failed to setup db: %s", err) 30 + } 26 31 27 - mux, err := routes.Setup(c) 32 + mux, err := routes.Setup(c, db) 28 33 if err != nil { 29 34 log.Fatal(err) 30 35 } 36 + 37 + internalMux := routes.SetupInternal(c, db) 31 38 32 39 addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) 33 - log.Println("starting server on", addr) 34 - log.Fatal(http.ListenAndServe(addr, mux)) 40 + internalAddr := fmt.Sprintf("%s:%d", c.Server.InternalHost, c.Server.InternalPort) 41 + 42 + log.Println("starting main server on", addr) 43 + go http.ListenAndServe(addr, mux) 44 + 45 + log.Println("starting internal server on", internalAddr) 46 + log.Fatal(http.ListenAndServe(internalAddr, internalMux)) 35 47 }
+10 -2
cmd/repoguard/main.go
··· 143 143 } 144 144 145 145 func isAllowedUser(user, repoPath string) bool { 146 - pathUser := strings.Split(repoPath, "/")[0] 147 - return pathUser == user 146 + fullPath := filepath.Join(*baseDirFlag, repoPath) 147 + didPath := filepath.Join(fullPath, "did") 148 + 149 + didBytes, err := os.ReadFile(didPath) 150 + if err != nil { 151 + return false 152 + } 153 + 154 + allowedUser := strings.TrimSpace(string(didBytes)) 155 + return allowedUser == user 148 156 }
+2
config.yaml
··· 19 19 host: 0.0.0.0 20 20 port: 5555 21 21 dbpath: bild.db 22 + internalHost: 127.0.0.1 23 + internalPort: 5444
+3
config/config.go
··· 30 30 Host string `yaml:"host"` 31 31 Port int `yaml:"port"` 32 32 DBPath string `yaml:"dbpath"` 33 + 34 + InternalHost string `yaml:"internalHost,omitempty"` 35 + InternalPort int `yaml:"internalPort,omitempty"` 33 36 } `yaml:"server"` 34 37 } 35 38
+27 -2
db/pubkeys.go
··· 17 17 type PublicKey struct { 18 18 Key string 19 19 Name string 20 + DID string 20 21 Created time.Time 21 22 } 22 23 24 + func (d *DB) GetAllPublicKeys() ([]PublicKey, error) { 25 + var keys []PublicKey 26 + 27 + rows, err := d.db.Query(`select key, name, did, created from public_keys`) 28 + if err != nil { 29 + return nil, err 30 + } 31 + defer rows.Close() 32 + 33 + for rows.Next() { 34 + var publicKey PublicKey 35 + if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.DID, &publicKey.Created); err != nil { 36 + return nil, err 37 + } 38 + keys = append(keys, publicKey) 39 + } 40 + 41 + if err := rows.Err(); err != nil { 42 + return nil, err 43 + } 44 + 45 + return keys, nil 46 + } 47 + 23 48 func (d *DB) GetPublicKeys(did string) ([]PublicKey, error) { 24 49 var keys []PublicKey 25 50 26 - rows, err := d.db.Query(`select key, name, created from public_keys where did = ?`, did) 51 + rows, err := d.db.Query(`select did, key, name, created from public_keys where did = ?`, did) 27 52 if err != nil { 28 53 return nil, err 29 54 } ··· 31 56 32 57 for rows.Next() { 33 58 var publicKey PublicKey 34 - if err := rows.Scan(&publicKey.Key, &publicKey.Name, &publicKey.Created); err != nil { 59 + if err := rows.Scan(&publicKey.DID, &publicKey.Key, &publicKey.Name, &publicKey.Created); err != nil { 35 60 return nil, err 36 61 } 37 62 keys = append(keys, publicKey)
+1 -6
routes/handler.go
··· 37 37 } 38 38 } 39 39 40 - func Setup(c *config.Config) (http.Handler, error) { 40 + func Setup(c *config.Config, db *db.DB) (http.Handler, error) { 41 41 r := chi.NewRouter() 42 42 s := sessions.NewCookieStore([]byte("TODO_CHANGE_ME")) 43 43 t, err := tmpl.Load(c.Dirs.Templates) ··· 46 46 } 47 47 48 48 auth := auth.NewAuth(s) 49 - 50 - db, err := db.Setup(c.Server.DBPath) 51 - if err != nil { 52 - return nil, fmt.Errorf("failed to setup db: %w", err) 53 - } 54 49 55 50 h := Handle{ 56 51 c: c,
+62
routes/internal.go
··· 1 + package routes 2 + 3 + import ( 4 + "encoding/json" 5 + "net/http" 6 + 7 + "github.com/go-chi/chi/v5" 8 + "github.com/icyphox/bild/config" 9 + "github.com/icyphox/bild/db" 10 + ) 11 + 12 + type InternalHandle struct { 13 + c *config.Config 14 + db *db.DB 15 + } 16 + 17 + func SetupInternal(c *config.Config, db *db.DB) http.Handler { 18 + ih := &InternalHandle{ 19 + c: c, 20 + db: db, 21 + } 22 + 23 + r := chi.NewRouter() 24 + r.Route("/internal/allkeys", func(r chi.Router) { 25 + r.Get("/", ih.AllKeys) 26 + }) 27 + 28 + return r 29 + } 30 + 31 + func (h *InternalHandle) returnJSON(w http.ResponseWriter, data interface{}) error { 32 + w.Header().Set("Content-Type", "application/json") 33 + res, err := json.Marshal(data) 34 + if err != nil { 35 + return err 36 + } 37 + _, err = w.Write(res) 38 + return err 39 + } 40 + 41 + func (h *InternalHandle) returnErr(w http.ResponseWriter, err error) error { 42 + w.WriteHeader(http.StatusInternalServerError) 43 + return h.returnJSON(w, map[string]string{ 44 + "error": err.Error(), 45 + }) 46 + } 47 + 48 + func (h *InternalHandle) AllKeys(w http.ResponseWriter, r *http.Request) { 49 + keys, err := h.db.GetAllPublicKeys() 50 + if err != nil { 51 + h.returnErr(w, err) 52 + return 53 + } 54 + keyMap := map[string]string{} 55 + for _, key := range keys { 56 + keyMap[key.DID] = key.Key 57 + } 58 + if err := h.returnJSON(w, keyMap); err != nil { 59 + h.returnErr(w, err) 60 + return 61 + } 62 + }
+10 -1
routes/routes.go
··· 524 524 name := r.FormValue("name") 525 525 description := r.FormValue("description") 526 526 527 - err := git.InitBare(filepath.Join(h.c.Repo.ScanPath, handle, name)) 527 + repoPath := filepath.Join(h.c.Repo.ScanPath, handle, name) 528 + err := git.InitBare(repoPath) 529 + if err != nil { 530 + h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") 531 + return 532 + } 533 + 534 + // For use by repoguard 535 + didPath := filepath.Join(repoPath, "did") 536 + err = os.WriteFile(didPath, []byte(did), 0644) 528 537 if err != nil { 529 538 h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.") 530 539 return