@@ -28,11 +28,11 @@ type SSHProxyConfig struct {
2828
2929// SSHProxy handles proxying SSH connections with credential injection
3030type SSHProxy struct {
31- config SSHProxyConfig
32- mutex sync.Mutex
33- sessionData []byte // Store session data for logging
34- inputBuffer []byte // Buffer for input data to batch keystrokes
35- inputChannelType session.TerminalChannelType // Channel type for buffered input
31+ config SSHProxyConfig
32+ mutex sync.Mutex
33+ sessionData []byte // Store session data for logging
34+ inputBuffer []byte // Buffer for input data to batch keystrokes
35+ inputChannelType session.TerminalChannelType // Channel type for buffered input
3636}
3737
3838// channelState holds per-channel state for tracking session type
@@ -510,20 +510,46 @@ func (p *SSHProxy) proxyData(src io.Reader, dst io.Writer, direction string, ses
510510 }
511511}
512512
513- // bufferInput accumulates input data and logs only when newline or control chars are encountered
513+ // bufferInput accumulates input data and logs the effective command after processing edits.
514+ // It interprets control characters (backspace, Ctrl+C/U/W) so that the logged command
515+ // reflects what the user actually sent, not the raw keystrokes.
514516func (p * SSHProxy ) bufferInput (data []byte , sessionID string , channelType session.TerminalChannelType ) {
515517 p .mutex .Lock ()
516518 defer p .mutex .Unlock ()
517519
518520 p .inputChannelType = channelType
519521
520522 for _ , b := range data {
521- p .inputBuffer = append (p .inputBuffer , b )
522-
523- // Check if we should flush the buffer
524- // CR (0x0D), LF (0x0A), or if buffer gets too large
525- if b == 0x0D || b == 0x0A || len (p .inputBuffer ) >= 1024 {
523+ switch b {
524+ case 0x7F , 0x08 : // DEL (backspace on most terminals) or BS
525+ if len (p .inputBuffer ) > 0 {
526+ p .inputBuffer = p .inputBuffer [:len (p .inputBuffer )- 1 ]
527+ }
528+ case 0x03 : // Ctrl+C - cancel current input
529+ p .inputBuffer = p .inputBuffer [:0 ]
530+ case 0x15 : // Ctrl+U - clear line
531+ p .inputBuffer = p .inputBuffer [:0 ]
532+ case 0x17 : // Ctrl+W - delete previous word
533+ // Skip trailing spaces
534+ for len (p .inputBuffer ) > 0 && p .inputBuffer [len (p .inputBuffer )- 1 ] == ' ' {
535+ p .inputBuffer = p .inputBuffer [:len (p .inputBuffer )- 1 ]
536+ }
537+ // Delete until next space or start
538+ for len (p .inputBuffer ) > 0 && p .inputBuffer [len (p .inputBuffer )- 1 ] != ' ' {
539+ p .inputBuffer = p .inputBuffer [:len (p .inputBuffer )- 1 ]
540+ }
541+ case 0x0D , 0x0A : // CR or LF - flush the buffer
542+ p .inputBuffer = append (p .inputBuffer , b )
526543 p .flushInputBufferUnsafe (sessionID )
544+ default :
545+ // Only buffer printable characters and tab
546+ if b >= 0x20 || b == 0x09 {
547+ p .inputBuffer = append (p .inputBuffer , b )
548+ }
549+ // Safety: flush if buffer gets too large
550+ if len (p .inputBuffer ) >= 1024 {
551+ p .flushInputBufferUnsafe (sessionID )
552+ }
527553 }
528554 }
529555}
0 commit comments