Monorepo for Tangled tangled.org
11

Configure Feed

Select the types of activity you want to include in your feed.

1package ssh 2 3import ( 4 "context" 5 "fmt" 6 "log/slog" 7 8 "github.com/charmbracelet/ssh" 9 "github.com/charmbracelet/wish" 10 tea "github.com/charmbracelet/wish/bubbletea" 11 "tangled.org/core/appview/config" 12 "tangled.org/core/appview/db" 13) 14 15type Server struct { 16 db *db.DB 17 config *config.Config 18 logger *slog.Logger 19} 20 21func New(db *db.DB, cfg *config.Config, logger *slog.Logger) *Server { 22 return &Server{db: db, config: cfg, logger: logger} 23} 24 25func (s *Server) ListenAndServe(ctx context.Context) error { 26 opts := []ssh.Option{ 27 wish.WithAddress(s.config.SSH.ListenAddr), 28 wish.WithMiddleware( 29 tea.Middleware(s.teaHandler), 30 requirePty, 31 ), 32 } 33 34 if s.config.SSH.HostKeyPath != "" { 35 opts = append(opts, wish.WithHostKeyPath(s.config.SSH.HostKeyPath)) 36 } 37 38 srv, err := wish.NewServer(opts...) 39 if err != nil { 40 return err 41 } 42 43 go func() { 44 <-ctx.Done() 45 s.logger.Info("shutting down SSH log server") 46 srv.Close() 47 }() 48 49 s.logger.Info("SSH log server listening", "address", s.config.SSH.ListenAddr) 50 if err := srv.ListenAndServe(); err != ssh.ErrServerClosed { 51 return err 52 } 53 s.logger.Info("SSH log server stopped") 54 return nil 55} 56 57// requirePty is a middleware that rejects connections without a PTY and tells the user to pass -t. 58func requirePty(next ssh.Handler) ssh.Handler { 59 return func(sess ssh.Session) { 60 _, _, ok := sess.Pty() 61 if !ok { 62 fmt.Fprintf(sess.Stderr(), "error: no terminal allocated\nhint: use `ssh -t` to force PTY allocation\n") 63 sess.Exit(1) 64 return 65 } 66 next(sess) 67 } 68}