repos / pico

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

pico / pkg / pssh
Antonio Mika  ·  2025-04-10

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 {
 34					if time.Now().After(afterTime) {
 35						break
 36					}
 37
 38					_, _, ok := sesh.Pty()
 39					if ok {
 40						break
 41					}
 42
 43					time.Sleep(50 * time.Millisecond)
 44				}
 45			}
 46
 47			_, _, ok := sesh.Pty()
 48			if !ok {
 49				return next(sesh)
 50			}
 51			return mdw(next)(sesh)
 52		}
 53	}
 54}
 55
 56type Window struct {
 57	Width        int
 58	Height       int
 59	HeightPixels int
 60	WidthPixels  int
 61}
 62
 63type Pty struct {
 64	Term   string
 65	Window Window
 66}
 67
 68func (p *Pty) Resize(width, height int) error {
 69	return nil
 70}
 71
 72func (p *Pty) Name() string {
 73	return ""
 74}
 75
 76func parsePtyRequest(s []byte) (pty Pty, ok bool) {
 77	term, s, ok := parseString(s)
 78	if !ok {
 79		return
 80	}
 81	width32, s, ok := parseUint32(s)
 82	if !ok {
 83		return
 84	}
 85	height32, _, ok := parseUint32(s)
 86	if !ok {
 87		return
 88	}
 89	pty = Pty{
 90		Term: term,
 91		Window: Window{
 92			Width:  int(width32),
 93			Height: int(height32),
 94		},
 95	}
 96	return
 97}
 98
 99func parseWinchRequest(s []byte) (win Window, ok bool) {
100	width32, s, ok := parseUint32(s)
101	if width32 < 1 {
102		ok = false
103	}
104	if !ok {
105		return
106	}
107	height32, _, ok := parseUint32(s)
108	if height32 < 1 {
109		ok = false
110	}
111	if !ok {
112		return
113	}
114	win = Window{
115		Width:  int(width32),
116		Height: int(height32),
117	}
118	return
119}
120
121func parseString(in []byte) (out string, rest []byte, ok bool) {
122	if len(in) < 4 {
123		return
124	}
125	length := binary.BigEndian.Uint32(in)
126	if uint32(len(in)) < 4+length {
127		return
128	}
129	out = string(in[4 : 4+length])
130	rest = in[4+length:]
131	ok = true
132	return
133}
134
135func parseUint32(in []byte) (uint32, []byte, bool) {
136	if len(in) < 4 {
137		return 0, nil, false
138	}
139	return binary.BigEndian.Uint32(in), in[4:], true
140}