1package internal
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/charmbracelet/keygen"
8 "github.com/charmbracelet/soft-serve/server/backend"
9 "github.com/charmbracelet/soft-serve/server/config"
10 "github.com/charmbracelet/soft-serve/server/hooks"
11 "github.com/charmbracelet/ssh"
12 "github.com/charmbracelet/wish"
13)
14
15// InternalServer is a internal interface to communicate with the server.
16type InternalServer struct {
17 cfg *config.Config
18 s *ssh.Server
19 kp *keygen.SSHKeyPair
20 ckp *keygen.SSHKeyPair
21}
22
23// NewInternalServer returns a new internal server.
24func NewInternalServer(cfg *config.Config, hooks hooks.Hooks) (*InternalServer, error) {
25 i := &InternalServer{cfg: cfg}
26
27 // Create internal key.
28 ikp, err := keygen.New(
29 cfg.Internal.InternalKeyPath,
30 keygen.WithKeyType(keygen.Ed25519),
31 keygen.WithWrite(),
32 )
33 if err != nil {
34 return nil, fmt.Errorf("internal key: %w", err)
35 }
36
37 i.kp = ikp
38
39 // Create client key.
40 ckp, err := keygen.New(
41 cfg.Internal.ClientKeyPath,
42 keygen.WithKeyType(keygen.Ed25519),
43 keygen.WithWrite(),
44 )
45 if err != nil {
46 return nil, fmt.Errorf("client key: %w", err)
47 }
48
49 i.ckp = ckp
50
51 s, err := wish.NewServer(
52 wish.WithAddress(cfg.Internal.ListenAddr),
53 wish.WithHostKeyPath(cfg.Internal.KeyPath),
54 wish.WithPublicKeyAuth(i.PublicKeyHandler),
55 wish.WithMiddleware(
56 i.Middleware(hooks),
57 ),
58 )
59 if err != nil {
60 return nil, fmt.Errorf("wish: %w", err)
61 }
62
63 i.s = s
64
65 return i, nil
66}
67
68// PublicKeyHandler handles public key authentication.
69func (i *InternalServer) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) bool {
70 return backend.KeysEqual(i.kp.PublicKey(), pk)
71}
72
73// Start starts the internal server.
74func (i *InternalServer) Start() error {
75 return i.s.ListenAndServe()
76}
77
78// Shutdown shuts down the internal server.
79func (i *InternalServer) Shutdown(ctx context.Context) error {
80 return i.s.Shutdown(ctx)
81}
82
83// Close closes the internal server.
84func (i *InternalServer) Close() error {
85 return i.s.Close()
86}