diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go index 187bfa0d5..0caf8d58e 100644 --- a/pkg/cmdrunner/cmdrunner.go +++ b/pkg/cmdrunner/cmdrunner.go @@ -565,7 +565,6 @@ func RemoteShowCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s return sstore.ModelUpdate{ Info: &sstore.InfoMsgType{ InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName), - InfoLines: splitLinesForInfo(buf.String()), PtyRemoteId: state.RemoteId, }, }, nil diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 38b8b3772..bc2aad142 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -23,6 +23,7 @@ import ( "github.com/scripthaus-dev/mshell/pkg/base" "github.com/scripthaus-dev/mshell/pkg/packet" "github.com/scripthaus-dev/mshell/pkg/shexec" + "github.com/scripthaus-dev/sh2-server/pkg/scpacket" "github.com/scripthaus-dev/sh2-server/pkg/sstore" ) @@ -30,7 +31,7 @@ const RemoteTypeMShell = "mshell" const DefaultTerm = "xterm-256color" const DefaultMaxPtySize = 1024 * 1024 const CircBufSize = 64 * 1024 -const RemoteTermRows = 10 +const RemoteTermRows = 8 const RemoteTermCols = 80 const PtyReadBufSize = 100 @@ -440,6 +441,29 @@ func MakeMShell(r *sstore.RemoteType) *MShellProc { return rtn } +func SendRemoteInput(pk *scpacket.RemoteInputPacketType) error { + data, err := base64.StdEncoding.DecodeString(pk.InputData64) + if err != nil { + return fmt.Errorf("cannot decode base64: %v\n", err) + } + msh := GetRemoteById(pk.RemoteId) + if msh == nil { + return fmt.Errorf("remote not found") + } + var cmdPty *os.File + msh.WithLock(func() { + cmdPty = msh.ControllingPty + }) + if cmdPty == nil { + return fmt.Errorf("remote has no attached pty") + } + _, err = cmdPty.Write(data) + if err != nil { + return fmt.Errorf("writing to pty: %v", err) + } + return nil +} + func convertSSHOpts(opts *sstore.SSHOpts) shexec.SSHOpts { if opts == nil || opts.Local { opts = &sstore.SSHOpts{} @@ -521,9 +545,9 @@ func (msh *MShellProc) writeToPtyBuffer_nolock(strFmt string, args ...interface{ realStr = realStr + "\r\n" } if strings.HasPrefix(realStr, "*") { - realStr = "\033[0m\033[31m[scripthaus]\033[0m " + realStr[1:] + realStr = "\033[0m\033[31mscripthaus>\033[0m " + realStr[1:] } else { - realStr = "\033[0m\033[32m[scripthaus]\033[0m " + realStr + realStr = "\033[0m\033[32mscripthaus>\033[0m " + realStr } barr := msh.PtyBuffer.Bytes() if len(barr) > 0 && barr[len(barr)-1] != '\n' { @@ -592,6 +616,8 @@ func (msh *MShellProc) Launch() { }() if remoteName == "test2" { go func() { + return + time.Sleep(2 * time.Second) cmdPty.Write([]byte(Test2Pw)) msh.WriteToPtyBuffer("~[password sent]\r\n") diff --git a/pkg/scpacket/scpacket.go b/pkg/scpacket/scpacket.go index 73c056971..aab8a9e31 100644 --- a/pkg/scpacket/scpacket.go +++ b/pkg/scpacket/scpacket.go @@ -11,6 +11,7 @@ import ( const FeCommandPacketStr = "fecmd" const WatchScreenPacketStr = "watchscreen" const FeInputPacketStr = "feinput" +const RemoteInputPacketStr = "remoteinput" type FeCommandPacketType struct { Type string `json:"type"` @@ -39,6 +40,12 @@ type FeInputPacketType struct { WinSize *packet.WinSize `json:"winsize,omitempty"` } +type RemoteInputPacketType struct { + Type string `json:"type"` + RemoteId string `json:"remoteid"` + InputData64 string `json:"inputdata64"` +} + type WatchScreenPacketType struct { Type string `json:"type"` SessionId string `json:"sessionid"` @@ -50,6 +57,7 @@ func init() { packet.RegisterPacketType(FeCommandPacketStr, reflect.TypeOf(FeCommandPacketType{})) packet.RegisterPacketType(WatchScreenPacketStr, reflect.TypeOf(WatchScreenPacketType{})) packet.RegisterPacketType(FeInputPacketStr, reflect.TypeOf(FeInputPacketType{})) + packet.RegisterPacketType(RemoteInputPacketStr, reflect.TypeOf(RemoteInputPacketType{})) } func (*FeCommandPacketType) GetType() string { @@ -75,3 +83,11 @@ func (*WatchScreenPacketType) GetType() string { func MakeWatchScreenPacket() *WatchScreenPacketType { return &WatchScreenPacketType{Type: WatchScreenPacketStr} } + +func MakeRemoteInputPacket() *RemoteInputPacketType { + return &RemoteInputPacketType{Type: RemoteInputPacketStr} +} + +func (*RemoteInputPacketType) GetType() string { + return RemoteInputPacketStr +} diff --git a/pkg/scws/scws.go b/pkg/scws/scws.go index 7326aa4b4..71e91c92a 100644 --- a/pkg/scws/scws.go +++ b/pkg/scws/scws.go @@ -178,7 +178,7 @@ func (ws *WSState) RunWSRead() { fmt.Printf("error unmarshalling ws message: %v\n", err) continue } - if pk.GetType() == "feinput" { + if pk.GetType() == scpacket.FeInputPacketStr { feInputPk := pk.(*scpacket.FeInputPacketType) if feInputPk.Remote.OwnerId != "" { fmt.Printf("[error] cannot send input to remote with ownerid\n") @@ -189,6 +189,7 @@ func (ws *WSState) RunWSRead() { continue } go func() { + // TODO enforce a strong ordering (channel with list) err = sendCmdInput(feInputPk) if err != nil { fmt.Printf("[error] sending command input: %v\n", err) @@ -196,7 +197,7 @@ func (ws *WSState) RunWSRead() { }() continue } - if pk.GetType() == "watchscreen" { + if pk.GetType() == scpacket.WatchScreenPacketStr { wsPk := pk.(*scpacket.WatchScreenPacketType) err := ws.handleWatchScreen(wsPk) if err != nil { @@ -205,6 +206,20 @@ func (ws *WSState) RunWSRead() { } continue } + if pk.GetType() == scpacket.RemoteInputPacketStr { + inputPk := pk.(*scpacket.RemoteInputPacketType) + if inputPk.RemoteId == "" { + fmt.Printf("[error] invalid remoteinput packet, remoteid is not set\n") + continue + } + go func() { + err = remote.SendRemoteInput(inputPk) + if err != nil { + fmt.Printf("[error] processing remote input: %v\n", err) + } + }() + continue + } fmt.Printf("got ws bad message: %v\n", pk.GetType()) } }