repos / pico

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

pico / pkg / pssh
Eric Bower  ·  2025-05-24

pty.go

  1package pssh
  2
  3import (
  4	"encoding/binary"
  5	"fmt"
  6	"time"
  7)
  8
  9func SessionMessage(sesh *SSHServerConnSession, msg string) {
 10	_, _ = sesh.Write([]byte(msg + "\r\n"))
 11}
 12
 13func DeprecatedNotice() SSHServerMiddleware {
 14	return func(next SSHServerHandler) SSHServerHandler {
 15		return func(sesh *SSHServerConnSession) error {
 16			msg := fmt.Sprintf(
 17				"%s\r\n\r\nRun %s to access pico's TUI",
 18				"DEPRECATED",
 19				"ssh pico.sh",
 20			)
 21			SessionMessage(sesh, msg)
 22			return next(sesh)
 23		}
 24	}
 25}
 26
 27func PtyMdw(mdw SSHServerMiddleware, waitTimeout time.Duration) SSHServerMiddleware {
 28	return func(next SSHServerHandler) SSHServerHandler {
 29		return func(sesh *SSHServerConnSession) error {
 30			if waitTimeout > 0 {
 31				afterTime := time.Now().Add(waitTimeout)
 32
 33				for time.Now().After(afterTime) {
 34					_, _, ok := sesh.Pty()
 35					if ok {
 36						break
 37					}
 38
 39					time.Sleep(50 * time.Millisecond)
 40				}
 41			}
 42
 43			_, _, ok := sesh.Pty()
 44			if !ok {
 45				return next(sesh)
 46			}
 47			return mdw(next)(sesh)
 48		}
 49	}
 50}
 51
 52type Window struct {
 53	Width        int
 54	Height       int
 55	HeightPixels int
 56	WidthPixels  int
 57}
 58
 59type Pty struct {
 60	Term   string
 61	Window Window
 62}
 63
 64func (p *Pty) Resize(width, height int) error {
 65	return nil
 66}
 67
 68func (p *Pty) Name() string {
 69	return ""
 70}
 71
 72func parsePtyRequest(s []byte) (pty Pty, ok bool) {
 73	term, s, ok := parseString(s)
 74	if !ok {
 75		return
 76	}
 77	width32, s, ok := parseUint32(s)
 78	if !ok {
 79		return
 80	}
 81	height32, _, ok := parseUint32(s)
 82	if !ok {
 83		return
 84	}
 85	pty = Pty{
 86		Term: term,
 87		Window: Window{
 88			Width:  int(width32),
 89			Height: int(height32),
 90		},
 91	}
 92	return
 93}
 94
 95func parseWinchRequest(s []byte) (win Window, ok bool) {
 96	width32, s, ok := parseUint32(s)
 97	if width32 < 1 {
 98		ok = false
 99	}
100	if !ok {
101		return
102	}
103	height32, _, ok := parseUint32(s)
104	if height32 < 1 {
105		ok = false
106	}
107	if !ok {
108		return
109	}
110	win = Window{
111		Width:  int(width32),
112		Height: int(height32),
113	}
114	return
115}
116
117func parseString(in []byte) (out string, rest []byte, ok bool) {
118	if len(in) < 4 {
119		return
120	}
121	length := binary.BigEndian.Uint32(in)
122	if uint32(len(in)) < 4+length {
123		return
124	}
125	out = string(in[4 : 4+length])
126	rest = in[4+length:]
127	ok = true
128	return
129}
130
131func parseUint32(in []byte) (uint32, []byte, bool) {
132	if len(in) < 4 {
133		return 0, nil, false
134	}
135	return binary.BigEndian.Uint32(in), in[4:], true
136}