main pico / pkg / pssh / pty.go
Antonio Mika  ·  2026-10-22
  1package pssh
  2
  3import (
  4	"encoding/binary"
  5	"strings"
  6)
  7
  8func SessionMessage(sesh *SSHServerConnSession, msg string) {
  9	_, _ = sesh.Write([]byte(msg + "\r\n"))
 10}
 11
 12// HelpNotice writes help to the session, translating newlines for the client's pty.
 13func HelpNotice(help string) SSHServerMiddleware {
 14	return func(next SSHServerHandler) SSHServerHandler {
 15		return func(sesh *SSHServerConnSession) error {
 16			SessionMessage(sesh, strings.ReplaceAll(strings.TrimRight(help, "\n"), "\n", "\r\n"))
 17			return next(sesh)
 18		}
 19	}
 20}
 21
 22func PtyMdw(mdw SSHServerMiddleware) SSHServerMiddleware {
 23	return func(next SSHServerHandler) SSHServerHandler {
 24		return func(sesh *SSHServerConnSession) error {
 25			_, _, ok := sesh.Pty()
 26			if !ok {
 27				return next(sesh)
 28			}
 29			return mdw(next)(sesh)
 30		}
 31	}
 32}
 33
 34type Window struct {
 35	Width        int
 36	Height       int
 37	HeightPixels int
 38	WidthPixels  int
 39}
 40
 41type Pty struct {
 42	Term   string
 43	Window Window
 44}
 45
 46func (p *Pty) Resize(width, height int) error {
 47	return nil
 48}
 49
 50func (p *Pty) Name() string {
 51	return ""
 52}
 53
 54func parsePtyRequest(s []byte) (pty Pty, ok bool) {
 55	term, s, ok := parseString(s)
 56	if !ok {
 57		return
 58	}
 59	width32, s, ok := parseUint32(s)
 60	if !ok {
 61		return
 62	}
 63	height32, _, ok := parseUint32(s)
 64	if !ok {
 65		return
 66	}
 67	pty = Pty{
 68		Term: term,
 69		Window: Window{
 70			Width:  int(width32),
 71			Height: int(height32),
 72		},
 73	}
 74	return
 75}
 76
 77func parseWinchRequest(s []byte) (win Window, ok bool) {
 78	width32, s, ok := parseUint32(s)
 79	if width32 < 1 {
 80		ok = false
 81	}
 82	if !ok {
 83		return
 84	}
 85	height32, _, ok := parseUint32(s)
 86	if height32 < 1 {
 87		ok = false
 88	}
 89	if !ok {
 90		return
 91	}
 92	win = Window{
 93		Width:  int(width32),
 94		Height: int(height32),
 95	}
 96	return
 97}
 98
 99func parseString(in []byte) (out string, rest []byte, ok bool) {
100	if len(in) < 4 {
101		return
102	}
103	length := binary.BigEndian.Uint32(in)
104	if uint32(len(in)) < 4+length {
105		return
106	}
107	out = string(in[4 : 4+length])
108	rest = in[4+length:]
109	ok = true
110	return
111}
112
113func parseUint32(in []byte) (uint32, []byte, bool) {
114	if len(in) < 4 {
115		return 0, nil, false
116	}
117	return binary.BigEndian.Uint32(in), in[4:], true
118}