You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tty-share/main.go

140 lines
3.6 KiB
Go

package main
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io"
"net"
"os"
"strings"
logrus "github.com/sirupsen/logrus"
)
var log = logrus.New()
var version string = "0.0.0"
func main() {
commandName := flag.String("command", os.Getenv("SHELL"), "The command to run")
if *commandName == "" {
*commandName = "bash"
}
commandArgs := flag.String("args", "", "The command arguments")
logFileName := flag.String("logfile", "-", "The name of the file to log")
useTLS := flag.Bool("useTLS", true, "Use TLS to connect to the server")
server := flag.String("server", "go.tty-share.com:7654", "tty-server address")
versionFlag := flag.Bool("version", false, "Print the tty-share version")
flag.Parse()
if *versionFlag {
fmt.Printf("%s\n", version)
return
}
log.Level = logrus.ErrorLevel
if *logFileName != "-" {
fmt.Printf("Writing logs to: %s\n", *logFileName)
logFile, err := os.Create(*logFileName)
if err != nil {
fmt.Printf("Can't open %s for writing logs\n", *logFileName)
}
log.Level = logrus.DebugLevel
log.Out = logFile
}
// TODO: check we are running inside a tty environment, and exit if not
var rawConnection io.ReadWriteCloser
if *useTLS {
roots, err := x509.SystemCertPool()
if err != nil {
fmt.Printf("Cannot connect to the server (%s): %s", *server, err.Error())
return
}
rawConnection, err = tls.Dial("tcp", *server, &tls.Config{RootCAs: roots})
if err != nil {
fmt.Printf("Cannot connect (TLS) to the server (%s): %s", *server, err.Error())
return
}
} else {
var err error
rawConnection, err = net.Dial("tcp", *server)
if err != nil {
fmt.Printf("Cannot connect to the server (%s): %s", *server, err.Error())
return
}
}
serverConnection := NewTTYProtocolConn(rawConnection)
reply, err := serverConnection.InitSender(SenderSessionInfo{
Salt: "salt",
PasswordVerifierA: "PV_A",
})
if err != nil {
fmt.Printf("Cannot initialise the protocol connection: %s", err.Error())
return
}
log.Infof("Web terminal: %s", reply.URLWebReadWrite)
// Display the session information to the user, before showing any output from the command.
// Wait until the user presses Enter
fmt.Printf("Web terminal: %s\n\n\r", reply.URLWebReadWrite)
//TODO: if the user on the remote side presses keys, and so messages are sent back to the
// tty sender, they will be delivered all at once, after Enter has been pressed. Fix that.
ptyMaster := ptyMasterNew()
ptyMaster.Start(*commandName, strings.Fields(*commandArgs), func(cols, rows int) {
log.Infof("New window size: %dx%d", cols, rows)
serverConnection.SetWinSize(cols, rows)
})
if cols, rows, e := ptyMaster.GetWinSize(); e == nil {
serverConnection.SetWinSize(cols, rows)
}
allWriter := io.MultiWriter(os.Stdout, serverConnection)
go func() {
_, err := io.Copy(allWriter, ptyMaster)
if err != nil {
log.Error("Lost connection with the server.\n")
ptyMaster.Stop()
}
}()
go func() {
for {
msg, err := serverConnection.ReadMessage()
if err != nil {
fmt.Printf(" -- Finishing the server connection with error: %s", err.Error())
break
}
if msg.Type == MsgIDWrite {
var msgWrite MsgTTYWrite
json.Unmarshal(msg.Data, &msgWrite)
ptyMaster.Write(msgWrite.Data[:msgWrite.Size])
}
if msg.Type == MsgIDSenderNewReceiverConnected {
var msgReceiverConnected MsgTTYSenderNewReceiverConnected
json.Unmarshal(msg.Data, &msgReceiverConnected)
ptyMaster.Refresh()
fmt.Printf("New receiver connected: %s ", msgReceiverConnected.Name)
}
}
}()
go func() {
io.Copy(ptyMaster, os.Stdin)
}()
ptyMaster.Wait()
}