Reputation: 132
After piping in a command to stdin after running session.RequestPty()
and session.Shell()
, there's seemingly no way to tell when that command is either done executing so I can try to parse stdout myself, or any way to directly get the output from the command. Additionally, I would like to be able to tell if a command is waiting for an interaction like pushing Y or entering a password.
Relevant code:
func connectSSH(username, host, identity, proxy string, resolve js.Value, reject js.Value) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
log.Println("Dialing WebSocket...")
dialed, _, err := websocket.Dial(ctx, proxy, nil)
if err != nil {
log.Printf("Failed to dial WebSocket: %v", err)
return err
}
dialed.Ping(ctx)
log.Println("WebSocket connection dialed")
c := websocket.NetConn(context.Background(), dialed, websocket.MessageBinary)
log.Println("NetConn created")
signer, err := ssh.ParsePrivateKey([]byte(identity))
if err != nil {
reject.Invoke(err.Error())
return err
}
ncc, chans, reqs, err := ssh.NewClientConn(c, host, &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
if err != nil {
reject.Invoke(err.Error())
return err
}
client := ssh.NewClient(ncc, chans, reqs)
session, err := client.NewSession()
if err != nil {
reject.Invoke(err.Error())
return err
}
stdin, err := session.StdinPipe()
if err != nil {
reject.Invoke(err.Error())
return err
}
var stdoutBuf bytes.Buffer
session.Stdout = &stdoutBuf
stderr, err := session.StderrPipe()
if err != nil {
reject.Invoke(err.Error())
return err
}
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
log.Fatal("request for pseudo terminal failed: ", err)
reject.Invoke(err.Error())
return err
}
// Execute the user's login shell
if err := session.Shell(); err != nil {
reject.Invoke(err.Error())
return err
}
activeConnection = Connection{
nc: c,
client: client,
wc: dialed,
session: session,
stdin: &stdin,
stdout: &stdoutBuf,
stderr: &stderr,
}
resolve.Invoke()
return nil
}
func stdout(resolve, reject js.Value) {
if activeConnection == (Connection{}) {
reject.Invoke("no active connection")
return
}
resolve.Invoke(stripansi.Strip(activeConnection.stdout.String()))
}
func execute(command string, resolve, reject js.Value) {
if activeConnection == (Connection{}) {
reject.Invoke("no active connection")
return
}
n, err := (*activeConnection.stdin).Write([]byte(command + "\n"))
if err != nil {
log.Printf("Error writing command to stdin: %v", err)
reject.Invoke(err.Error())
return
}
log.Printf("Wrote %d bytes to stdin", n)
if closer, ok := (*activeConnection.stdin).(io.Closer); ok {
err = closer.Close()
if err != nil {
log.Printf("Error flushing stdin: %v", err)
reject.Invoke(err.Error())
return
}
}
resolve.Invoke(n)
}
Upvotes: 0
Views: 90