repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / apps / pipe
Eric Bower  ·  2025-05-25

ssh.go

  1package pipe
  2
  3import (
  4	"context"
  5	"os"
  6	"os/signal"
  7	"syscall"
  8
  9	"github.com/antoniomika/syncmap"
 10	"github.com/picosh/pico/pkg/db/postgres"
 11	"github.com/picosh/pico/pkg/pssh"
 12	"github.com/picosh/pico/pkg/shared"
 13	psub "github.com/picosh/pubsub"
 14	"github.com/picosh/utils"
 15	"golang.org/x/crypto/ssh"
 16)
 17
 18func StartSshServer() {
 19	appName := "pipe-ssh"
 20
 21	host := utils.GetEnv("PIPE_HOST", "0.0.0.0")
 22	port := utils.GetEnv("PIPE_SSH_PORT", "2222")
 23	portOverride := utils.GetEnv("PIPE_SSH_PORT_OVERRIDE", port)
 24	promPort := utils.GetEnv("PIPE_PROM_PORT", "9222")
 25	cfg := NewConfigSite(appName)
 26	logger := cfg.Logger
 27
 28	ctx, cancel := context.WithCancel(context.Background())
 29	defer cancel()
 30
 31	dbh := postgres.NewDB(cfg.DbURL, cfg.Logger)
 32	defer func() {
 33		_ = dbh.Close()
 34	}()
 35
 36	cfg.Port = port
 37	cfg.PortOverride = portOverride
 38
 39	pubsub := psub.NewMulticast(logger)
 40	handler := &CliHandler{
 41		Logger:  logger,
 42		DBPool:  dbh,
 43		PubSub:  pubsub,
 44		Cfg:     cfg,
 45		Waiters: syncmap.New[string, []string](),
 46		Access:  syncmap.New[string, []string](),
 47	}
 48
 49	sshAuth := shared.NewSshAuthHandler(dbh, logger)
 50
 51	// Create a new SSH server
 52	server, err := pssh.NewSSHServerWithConfig(
 53		ctx,
 54		logger,
 55		appName,
 56		host,
 57		port,
 58		promPort,
 59		"ssh_data/term_info_ed25519",
 60		func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
 61			perms, _ := sshAuth.PubkeyAuthHandler(conn, key)
 62			if perms == nil {
 63				perms = &ssh.Permissions{
 64					Extensions: map[string]string{
 65						"pubkey": utils.KeyForKeyText(key),
 66					},
 67				}
 68			}
 69
 70			return perms, nil
 71		},
 72		[]pssh.SSHServerMiddleware{
 73			Middleware(handler),
 74			pssh.LogMiddleware(handler, dbh),
 75		},
 76		nil,
 77		nil,
 78	)
 79
 80	if err != nil {
 81		logger.Error("failed to create ssh server", "err", err.Error())
 82		os.Exit(1)
 83	}
 84
 85	done := make(chan os.Signal, 1)
 86	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
 87	logger.Info("Starting SSH server", "addr", server.Config.ListenAddr)
 88	go func() {
 89		if err = server.ListenAndServe(); err != nil {
 90			logger.Error("serve", "err", err.Error())
 91			os.Exit(1)
 92		}
 93	}()
 94
 95	exit := func() {
 96		logger.Info("stopping ssh server")
 97		cancel()
 98	}
 99
100	<-done
101	exit()
102}