Eric Bower
·
2026-01-25
ssh.go
1package prose
2
3import (
4 "context"
5 "os"
6 "os/signal"
7 "syscall"
8 "time"
9
10 "github.com/picosh/pico/pkg/db/postgres"
11 "github.com/picosh/pico/pkg/filehandlers"
12 uploadimgs "github.com/picosh/pico/pkg/filehandlers/imgs"
13 "github.com/picosh/pico/pkg/pssh"
14 "github.com/picosh/pico/pkg/send/auth"
15 "github.com/picosh/pico/pkg/send/list"
16 "github.com/picosh/pico/pkg/send/pipe"
17 "github.com/picosh/pico/pkg/send/protocols/rsync"
18 "github.com/picosh/pico/pkg/send/protocols/scp"
19 "github.com/picosh/pico/pkg/send/protocols/sftp"
20 "github.com/picosh/pico/pkg/shared"
21 "github.com/picosh/pico/pkg/shared/storage"
22)
23
24func StartSshServer() {
25 appName := "prose-ssh"
26
27 host := shared.GetEnv("PROSE_HOST", "0.0.0.0")
28 port := shared.GetEnv("PROSE_SSH_PORT", "2222")
29 promPort := shared.GetEnv("PROSE_PROM_PORT", "9222")
30 cfg := NewConfigSite(appName)
31 logger := cfg.Logger
32
33 ctx, cancel := context.WithCancel(context.Background())
34 defer cancel()
35
36 dbh := postgres.NewDB(cfg.DbURL, cfg.Logger)
37 defer func() {
38 _ = dbh.Close()
39 }()
40
41 hooks := &MarkdownHooks{
42 Cfg: cfg,
43 Db: dbh,
44 }
45
46 adapter := storage.GetStorageTypeFromEnv()
47 st, err := storage.NewStorage(cfg.Logger, adapter)
48 if err != nil {
49 logger.Error("loading storage", "err", err)
50 return
51 }
52
53 fileMap := map[string]filehandlers.ReadWriteHandler{
54 ".md": filehandlers.NewScpPostHandler(dbh, cfg, hooks),
55 ".txt": filehandlers.NewScpPostHandler(dbh, cfg, hooks),
56 ".css": filehandlers.NewScpPostHandler(dbh, cfg, hooks),
57 ".lxt": filehandlers.NewScpPostHandler(dbh, cfg, hooks),
58 "fallback": uploadimgs.NewUploadImgHandler(dbh, cfg, st),
59 }
60 handler := filehandlers.NewFileHandlerRouter(cfg, dbh, fileMap)
61
62 sshAuth := shared.NewSshAuthHandler(dbh, logger, "prose")
63
64 // Create a new SSH server
65 server, err := pssh.NewSSHServerWithConfig(
66 ctx,
67 logger,
68 appName,
69 host,
70 port,
71 promPort,
72 "ssh_data/term_info_ed25519",
73 sshAuth.PubkeyAuthHandler,
74 []pssh.SSHServerMiddleware{
75 pipe.Middleware(handler, ".md"),
76 list.Middleware(handler),
77 scp.Middleware(handler),
78 rsync.Middleware(handler),
79 auth.Middleware(handler),
80 pssh.PtyMdw(pssh.DeprecatedNotice(), 200*time.Millisecond),
81 pssh.LogMiddleware(handler, dbh),
82 },
83 []pssh.SSHServerMiddleware{
84 sftp.Middleware(handler),
85 pssh.LogMiddleware(handler, dbh),
86 },
87 nil,
88 )
89
90 if err != nil {
91 logger.Error("failed to create ssh server", "err", err.Error())
92 os.Exit(1)
93 }
94
95 done := make(chan os.Signal, 1)
96 signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
97 logger.Info("Starting SSH server", "addr", server.Config.ListenAddr)
98 go func() {
99 if err = server.ListenAndServe(); err != nil {
100 logger.Error("serve", "err", err.Error())
101 os.Exit(1)
102 }
103 }()
104
105 exit := func() {
106 logger.Info("stopping ssh server")
107 cancel()
108 }
109
110 <-done
111 exit()
112}