I am working on app, needs to manage ssh. so I used ssh module and as i needed, using StdoutPipe expect of session.Stdout.
by the way, in some situation, I got output with specific character
My problem is: there are some specific character (here backspace), that are handled correctly when using fmt.Println(). but it will be printed in sample files out.log!. so it exists in text too. How can I handle them? in another word; how can I convert them to printable format and store then in the string variable
stdOutputResult := []byte{114, 111, 111, 116, 64, 100, 101, 98, 105, 97, 110, 58, 126, 35, 32, 104, 101, 108, 108, 111, 8, 8, 8, 8, 8, 116, 101, 115, 116, 50, 8, 8, 8, 120, 116, 49}
text := string(stdOutputResult)
fmt.Println("len(stdOutputResult):", len(stdOutputResult))
fmt.Println("len(text):", len(text))
fmt.Println(text)
ioutil.WriteFile("out.log", []byte(text), 0644)
cli output:
len(stdOutputResult): 36
len(text): 36
root@debian:~# text1
file output 'out.log':
root@debian:~# helloBSBSBSBSBStest2BSBSBSxt1
here is part of my code:
import (
"bufio"
"fmt"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
"log"
"net"
"os"
"os/exec"
"strings"
)
type Connection struct {
*ssh.Client
password string
}
func connectServer(addr, user, password string) (sInfo *SessionInfo, err error){
conn, err := dialSSH(addr, user, password)
if err != nil {
return nil, err
}
closeGoRoutines := false
quit2 := make(chan bool)
quit4 := make(chan bool)
session, err := conn.NewSession()
if err != nil {
panic("Failed to create session: " + err.Error())
}
defer session.Close()
//// Set IO
//session.Stdout = os.Stdout
sessionStdout, _ := session.StdoutPipe()
session.Stderr = os.Stderr
in, _ := session.StdinPipe()
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
fileDescriptor := int(os.Stdin.Fd())
if terminal.IsTerminal(fileDescriptor) {
originalState, err := terminal.MakeRaw(fileDescriptor)
if err != nil {
}
defer terminal.Restore(fileDescriptor, originalState)
termWidth, termHeight, err := terminal.GetSize(fileDescriptor)
if err != nil {
}
//err = session.RequestPty("xterm-256color", termHeight, termWidth, modes)
err = session.RequestPty("xterm", termHeight, termWidth, modes)
//err = session.RequestPty("dumb", termHeight, termWidth, modes)
if err != nil {
}
}
// Start remote shell
if err := session.Shell(); err != nil {
log.Fatalf("failed to start shell: %s", err)
}
// handle stdout
//chanStdout := make(chan string)
chanStdout := make(chan byte)
go func(ch chan byte) {
r := bufio.NewReader(sessionStdout)
for {
var b []byte = make([]byte, 1)
_, err := r.Read(b)
//if err != nil && err == io.EOF {
if err != nil{
prepareToExit()
closeGoRoutines = true
quit2 <- true
quit4 <- true
return
}
//w.Write(b)
chanStdout <- b[0]
//chanStdout <- string(b)
}
}(chanStdout)
lastoutLine := ""
sInfo = NewSessionInfo()
go func() {
for {
select {
case <-quit2:
return
case stdout, _ := <-chanStdout:
sInfo.AddToCLI(stdout)
}
}
}()
stdinLine := ""
go func() {
//disable input buffering
exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()
//do not display entered characters on the screen
exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
//fmt.Fprint(in, "bind 'set bell-style none'\n")
fmt.Fprint(in, "sudo -i\n")
var b []byte = make([]byte, 1)
for {
_ , err := os.Stdin.Read(b)
if err != nil{
return
}
if closeGoRoutines{
return
}
stdin := b[0]
if stdin == 13 || stdin == 10 {
//fmt.Println("------------"+stdinLine+"-")
if stdinLine == "ssmgo" {
fmt.Println("\r\nyou'r morteza iravani")
}
if ! isCommandAllowed(stdinLine, lastoutLine){
stdinLine = ""
fmt.Println("command not allowed")
continue
}
sInfo.appendHistory(stdinLine)
//sInfo.appendHistoryFromSTDIN(stdinLine)
//print("<" + lastoutLine + ">")
//lastoutLine = ""
//historyBashOld = append(historyBashOld, sInfo.command)
stdinLine = ""
//con
} else {
stdinLine = stdinLine + string(stdin)
//fmt.Println(stdinLine)
}
in.Write(b)
//ch <- b[0]
}
}()
<- quit4
return
}
func dialSSH(addr, user, password string) (*Connection, error) {
sshConfig := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
HostKeyCallback: ssh.HostKeyCallback(func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }),
}
conn, err := ssh.Dial("tcp", addr, sshConfig)
if err != nil {
return nil, err
}
return &Connection{conn, password}, nil
}
func isCommandAllowed(line, lastoutLine string) bool {
if len(line) > 0 {
cmd := strings.Split(line, " ")[0]
//fmt.Println(" is ("+cmd+") ["+lastoutLine+"] banded:" + string(bandedCommands[cmd]))
_, exist := bandedCommands[cmd]
return !exist
}
return true
}
func prepareToExit(){
exec.Command("stty", "-F", "/dev/tty", "sane").Run()
}