This repository has been archived on 2023-07-12. You can view files and clone it, but cannot push or open issues or pull requests.
sshoneypot/sshoneypot/info/terminal.go
2022-04-28 20:01:08 +02:00

180 lines
3.1 KiB
Go

package info
import (
"errors"
"fmt"
"golang.org/x/crypto/ssh"
"strconv"
"sync"
)
type Terminal struct {
// the chan
channel ssh.Channel
// The current prompt string
prompt string
width, height int
isListening bool
buffer []byte
lock *sync.Mutex
}
const (
keyCtrlC = 3
keyCtrlD = 4
keyEnter = 13
keyEscape = 27
keyReturn = 127
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
keyUp
keyDown
keyLeft
keyRight
keyAltLeft
keyAltRight
keyHome
keyEnd
keyDeleteWord
keyDeleteLine
keyClearScreen
keyPasteStart
keyPasteEnd
)
var (
CtrlC = errors.New("CtrlC")
CtrlD = errors.New("CtrlD")
)
func (term *Terminal) GetSize() (width int, height int) {
return term.width, term.height
}
func (term *Terminal) SetSize(width int, height int) {
term.width = width
term.height = height
}
func (term *Terminal) GetPrompt() string {
return term.prompt
}
func (term *Terminal) SetPrompt(prompt string) {
term.prompt = prompt
}
func (term *Terminal) ReadLine() (string, error) {
var content []byte
for {
data, _ := term.listen()
for _, b := range data {
fmt.Println(b)
switch []rune(data) {
case keyCtrlD:
if len(content) == 0 {
return "", CtrlD
}
case keyEnter:
term.channel.Write([]byte("\r\n" + term.prompt))
return string(data), nil
case keyReturn:
if len(content) - 1 > len(term.prompt) {
content = content[:len(content) - 1]
term.MoveCursor(0, 0, 1, 0)
term.channel.Write(content)
}
case keyRight:
fmt.Println("aaa")
default:
content = append(content, b)
term.channel.Write(data)
}
}
}
}
func (term *Terminal) Write(data []byte) (n int, err error) {
return term.channel.Write(data)
}
func (term *Terminal) MoveCursor(up, down, left, right int) {
var m []rune
// 1 unit up can be expressed as ^[[A or ^[A
// 5 units up can be expressed as ^[[5A
if up == 1 {
m = append(m, keyEscape, '[', 'A')
} else if up > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(up))...)
m = append(m, 'A')
}
if down == 1 {
m = append(m, keyEscape, '[', 'B')
} else if down > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(down))...)
m = append(m, 'B')
}
if right == 1 {
m = append(m, keyEscape, '[', 'C')
} else if right > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(right))...)
m = append(m, 'C')
}
if left == 1 {
m = append(m, keyEscape, '[', 'D')
} else if left > 1 {
m = append(m, keyEscape, '[')
m = append(m, []rune(strconv.Itoa(left))...)
m = append(m, 'D')
}
term.Write([]byte(string(m)))
}
func (term *Terminal) ListenCtrlC() chan bool {
ctrlc := make(chan bool, 1)
go func() {
if term.isListening {
return
}
for {
data, err := term.listen()
if err == CtrlC {
ctrlc <- false
return
}
if term.isListening {
ctrlc <- false
term.buffer = data
}
}
}()
return ctrlc
}
func (term *Terminal) listen() ([]byte, error) {
buffer := make([]byte, 512)
n, err := term.channel.Read(buffer)
return buffer[:n], err
}
func NewTerminal(channel ssh.Channel) *Terminal {
return &Terminal{
channel: channel,
lock: &sync.Mutex{},
}
}