main
ssh.go
Eric Bower
·
2026-02-25
1package patchbin
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "path/filepath"
8 "time"
9
10 "github.com/picosh/pico/pkg/pssh"
11 "golang.org/x/crypto/ssh"
12)
13
14func authHandler(pr *PrCmd) func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
15 return func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
16 pubkey := pr.Backend.Pubkey(key)
17 userName := conn.User()
18 perms := &ssh.Permissions{
19 Extensions: map[string]string{
20 "pubkey": pubkey,
21 },
22 }
23 err := pr.IsBanned(pubkey, userName)
24 if err != nil {
25 pr.Backend.Logger.Info(
26 "user denied access",
27 "err", err,
28 "username", userName,
29 "pubkey", pubkey,
30 )
31 return perms, err
32 }
33 return perms, nil
34 }
35}
36
37func GitSshServer(ctx context.Context, cfg *GitCfg) *pssh.SSHServer {
38 dbpath := filepath.Join(cfg.DataDir, "pr.db?_fk=on")
39 dbh, err := SqliteOpen("file:"+dbpath, cfg.Logger)
40 if err != nil {
41 panic(fmt.Sprintf("cannot find database file, check folder and perms: %s: %s", dbpath, err))
42 }
43
44 interval, err := time.ParseDuration(cfg.RateLimitInterval)
45 if err != nil {
46 panic(fmt.Sprintf("invalid rate_limit_interval: %s: %s", cfg.RateLimitInterval, err))
47 }
48
49 be := &Backend{
50 DB: dbh,
51 Logger: cfg.Logger,
52 Cfg: cfg,
53 Limiter: NewRateLimiter(cfg.RateLimitCount, interval),
54 }
55
56 prCmd := &PrCmd{
57 Backend: be,
58 }
59
60 server, err := pssh.NewSSHServerWithConfig(
61 ctx,
62 cfg.Logger,
63 "patchbin",
64 cfg.Host,
65 cfg.SshPort,
66 cfg.PromPort,
67 filepath.Join(cfg.DataDir, "term_info_ed25519"),
68 authHandler(prCmd),
69 []pssh.SSHServerMiddleware{
70 GitPatchRequestMiddleware(be, prCmd),
71 },
72 []pssh.SSHServerMiddleware{},
73 nil,
74 )
75
76 if err != nil {
77 cfg.Logger.Error("failed to create ssh server", "err", err)
78 os.Exit(1)
79 }
80
81 return server
82}