+15
cmd/keyfetch/format.go
+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
+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
+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
+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
+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
+2
config.yaml
+3
config/config.go
+3
config/config.go
+27
-2
db/pubkeys.go
+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
+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
+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
+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