Eric Bower
·
2024-11-12
ssh.go
1package git
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "os/signal"
8 "path/filepath"
9 "syscall"
10 "time"
11
12 "github.com/charmbracelet/ssh"
13 "github.com/charmbracelet/wish"
14)
15
16func authHandler(pr *PrCmd) func(ctx ssh.Context, key ssh.PublicKey) bool {
17 return func(ctx ssh.Context, key ssh.PublicKey) bool {
18 pubkey := pr.Backend.Pubkey(key)
19 userName := ctx.User()
20 err := pr.IsBanned(pubkey, userName)
21 if err != nil {
22 pr.Backend.Logger.Info(
23 "user denied access",
24 "err", err,
25 "username", userName,
26 "pubkey", pubkey,
27 )
28 return false
29 }
30 return true
31 }
32}
33
34func GitSshServer(cfg *GitCfg, killCh chan error) {
35 dbpath := filepath.Join(cfg.DataDir, "pr.db?_fk=on")
36 dbh, err := SqliteOpen("file:"+dbpath, cfg.Logger)
37 if err != nil {
38 panic(fmt.Sprintf("cannot find database file, check folder and perms: %s: %s", dbpath, err))
39 }
40
41 be := &Backend{
42 DB: dbh,
43 Logger: cfg.Logger,
44 Cfg: cfg,
45 }
46 prCmd := &PrCmd{
47 Backend: be,
48 }
49
50 s, err := wish.NewServer(
51 wish.WithAddress(
52 fmt.Sprintf("%s:%s", cfg.Host, cfg.SshPort),
53 ),
54 wish.WithHostKeyPath(
55 filepath.Join(cfg.DataDir, "term_info_ed25519"),
56 ),
57 wish.WithPublicKeyAuth(authHandler(prCmd)),
58 wish.WithMiddleware(
59 GitPatchRequestMiddleware(be, prCmd),
60 ),
61 )
62
63 if err != nil {
64 cfg.Logger.Error("could not create server", "err", err)
65 return
66 }
67
68 done := make(chan os.Signal, 1)
69 signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
70 cfg.Logger.Info("starting SSH server", "host", cfg.Host, "port", cfg.SshPort)
71 go func() {
72 if err = s.ListenAndServe(); err != nil {
73 cfg.Logger.Error("serve error", "err", err)
74 // os.Exit(1)
75 }
76 }()
77
78 select {
79 case <-done:
80 case <-killCh:
81 }
82 cfg.Logger.Info("stopping SSH server")
83 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
84 defer func() { cancel() }()
85 if err := s.Shutdown(ctx); err != nil {
86 cfg.Logger.Error("shutdown", "err", err)
87 // os.Exit(1)
88 }
89}