- commit
- b10aef1
- parent
- 1f6cc61
- author
- Eric Bower
- date
- 2026-02-25 22:13:25 -0500 EST
fix(pssh): normalize line ending with pty
1 files changed,
+27,
-0
+27,
-0
1@@ -1,6 +1,7 @@
2 package pssh
3
4 import (
5+ "bytes"
6 "context"
7 "crypto/ed25519"
8 "crypto/rand"
9@@ -185,6 +186,32 @@ func (s *SSHServerConnSession) Pty() (*Pty, <-chan Window, bool) {
10 return s.pty, s.winch, true
11 }
12
13+// Write overrides the embedded Channel's Write to normalize line endings when PTY is allocated.
14+func (s *SSHServerConnSession) Write(p []byte) (n int, err error) {
15+ s.mu.Lock()
16+ hasPty := s.pty != nil
17+ s.mu.Unlock()
18+
19+ if !hasPty {
20+ // No PTY, write as-is
21+ return s.Channel.Write(p)
22+ }
23+
24+ // When PTY is active, normalize line endings like a real terminal would.
25+ // Replace \n with \r\n, but avoid double \r\n.
26+ normalized := bytes.ReplaceAll(p, []byte{'\n'}, []byte{'\r', '\n'})
27+ normalized = bytes.ReplaceAll(normalized, []byte{'\r', '\r', '\n'}, []byte{'\r', '\n'})
28+
29+ // Write the normalized data
30+ written, err := s.Channel.Write(normalized)
31+
32+ // Return the count based on original data length, not normalized
33+ if written > len(p) {
34+ written = len(p)
35+ }
36+ return written, err
37+}
38+
39 var _ context.Context = &SSHServerConnSession{}
40
41 func (sc *SSHServerConn) Handle(chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) error {