From 705287059f3fb774b7982899e2aaae708b0926d0 Mon Sep 17 00:00:00 2001 From: asimfarooq5 Date: Sat, 20 Sep 2025 16:24:10 +0500 Subject: [PATCH 1/4] Implement interactive shell support --- cmd/wsh/main.go | 138 ++++++++++++++++++++++++++++++++++------------ cmd/wshd/main.go | 139 ++++++++++++++++++++++++++++++++++++++++------- go.mod | 2 + go.sum | 4 ++ 4 files changed, 226 insertions(+), 57 deletions(-) diff --git a/cmd/wsh/main.go b/cmd/wsh/main.go index 5b406c7..bc97052 100644 --- a/cmd/wsh/main.go +++ b/cmd/wsh/main.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/jessevdk/go-flags" + "golang.org/x/term" "github.com/xconnio/berncrypt/go" "github.com/xconnio/wamp-webrtc-go" @@ -18,6 +19,8 @@ import ( const ( defaultRealm = "wampshell" + procedureInteractive = "wampshell.shell.interactive" + procedureExec = "wampshell.shell.exec" procedureWebRTCOffer = "wampshell.webrtc.offer" topicOffererOnCandidate = "wampshell.webrtc.offerer.on_candidate" topicAnswererOnCandidate = "wampshell.webrtc.answerer.on_candidate" @@ -65,11 +68,103 @@ func exchangeKeys(session *xconn.Session) (*keyPair, error) { }, nil } +func startInteractiveShell(session *xconn.Session, keys *keyPair) { + fd := int(os.Stdin.Fd()) + oldState, err := term.MakeRaw(fd) + if err != nil { + log.Fatalf("Failed to set raw mode: %s", err) + } + defer func(fd int, oldState *term.State) { + _ = term.Restore(fd, oldState) + }(fd, oldState) + + firstProgress := true + + call := session.Call(procedureInteractive). + ProgressSender(func(ctx context.Context) *xconn.Progress { + if firstProgress { + firstProgress = false + return xconn.NewProgress() + } + + buf := make([]byte, 1024) + n, err := os.Stdin.Read(buf) + if err != nil { + return xconn.NewFinalProgress() + } + + ciphertext, nonce, err := berncrypt.EncryptChaCha20Poly1305(buf[:n], keys.send) + if err != nil { + panic(err) + } + payload := append(nonce, ciphertext...) + + return xconn.NewProgress(payload) + }). + ProgressReceiver(func(result *xconn.InvocationResult) { + if len(result.Args) > 0 { + encData := result.Args[0].([]byte) + + if len(encData) < 12 { + fmt.Fprintln(os.Stderr, "invalid payload from server") + os.Exit(1) + } + + plain, err := berncrypt.DecryptChaCha20Poly1305(encData[12:], encData[:12], keys.receive) + if err != nil { + panic(err) + } + + os.Stdout.Write(plain) + } else { + err = term.Restore(fd, oldState) + if err != nil { + return + } + os.Exit(0) + } + }).Do() + + if call.Err != nil { + log.Fatalf("Shell error: %s", call.Err) + } +} + +func runCommand(session *xconn.Session, keys *keyPair, args []string) { + b := []byte(strings.Join(args, " ")) + + ciphertext, nonce, err := berncrypt.EncryptChaCha20Poly1305(b, keys.send) + if err != nil { + panic(err) + } + + payload := append(nonce, ciphertext...) + + cmdResponse := session.Call(procedureExec).Args(payload).Do() + if cmdResponse.Err != nil { + fmt.Printf("Command execution error: %v\n", cmdResponse.Err) + os.Exit(1) + } + + output, err := cmdResponse.Args.Bytes(0) + if err != nil { + fmt.Printf("Output parsing error: %v\n", err) + os.Exit(1) + } + + plain, err := berncrypt.DecryptChaCha20Poly1305(output[12:], output[:12], keys.receive) + if err != nil { + panic(err) + } + fmt.Print(string(plain)) +} + type Options struct { - PeerToPeer bool `long:"p2p" description:"Use WebRTC for peer-to-peer connection"` - Args struct { + Interactive bool `short:"i" long:"interactive" description:"Force interactive shell"` + PeerToPeer bool `long:"p2p" description:"Use WebRTC for peer-to-peer connection"` + Args struct { Target string `positional-arg-name:"host" required:"true"` - Cmd []string `positional-arg-name:"command" required:"true"` + Cmd []string `positional-arg-name:"command"` } `positional-args:"yes"` } @@ -105,11 +200,6 @@ func main() { port = "8022" } - anyArgs := make([]any, len(args)) - for i, a := range args { - anyArgs[i] = a - } - privateKey, err := wampshell.ReadPrivateKeyFromFile() if err != nil { fmt.Printf("Error reading private key: %v\n", err) @@ -118,7 +208,7 @@ func main() { authenticator, err := auth.NewCryptoSignAuthenticator("", privateKey, nil) if err != nil { - fmt.Printf("Error creating crypto sign authenticator: %v\n", err) + fmt.Printf("Error creating crypto sign authenticator: %v", err) os.Exit(1) } @@ -156,33 +246,9 @@ func main() { panic(err) } - b := []byte(strings.Join(args, " ")) - - ciphertext, nonce, err := berncrypt.EncryptChaCha20Poly1305(b, keys.send) - if err != nil { - panic(err) - } - - payload := make([]byte, len(nonce)+len(ciphertext)) - copy(payload, nonce) - copy(payload[len(nonce):], ciphertext) - - cmdResponse := session.Call("wampshell.shell.exec").Args(payload).Do() - if cmdResponse.Err != nil { - fmt.Printf("Command execution error: %v\n", cmdResponse.Err) - os.Exit(1) - } - - output, err := cmdResponse.Args.Bytes(0) - if err != nil { - fmt.Printf("Output parsing error: %v\n", err) - os.Exit(1) - } - - a, err := berncrypt.DecryptChaCha20Poly1305(output[12:], output[:12], keys.receive) - if err != nil { - panic(err) + if opts.Interactive || len(args) == 0 { + startInteractiveShell(session, keys) } - fmt.Print(string(a)) + runCommand(session, keys, args) } diff --git a/cmd/wshd/main.go b/cmd/wshd/main.go index 9fa9887..20b91b5 100644 --- a/cmd/wshd/main.go +++ b/cmd/wshd/main.go @@ -1,4 +1,3 @@ -// wshd.go package main import ( @@ -11,8 +10,9 @@ import ( "os/signal" "path/filepath" "strings" + "sync" - "github.com/jessevdk/go-flags" + "github.com/creack/pty" "github.com/xconnio/berncrypt/go" "github.com/xconnio/wamp-webrtc-go" @@ -25,6 +25,7 @@ const ( defaultRealm = "wampshell" defaultPort = 8022 defaultHost = "0.0.0.0" + procedureInteractive = "wampshell.shell.interactive" procedureExec = "wampshell.shell.exec" procedureFileUpload = "wampshell.shell.upload" procedureFileDownload = "wampshell.shell.download" @@ -33,15 +34,116 @@ const ( topicAnswererOnCandidate = "wampshell.webrtc.answerer.on_candidate" ) +type interactiveShellSession struct { + ptmx map[uint64]*os.File + sync.Mutex +} + +func newInteractiveShellSession() *interactiveShellSession { + return &interactiveShellSession{ + ptmx: make(map[uint64]*os.File), + } +} + +func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) func(_ context.Context, + inv *xconn.Invocation) *xconn.InvocationResult { + return func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { + caller := inv.Caller() + + e.Lock() + key, ok := e.Keys()[inv.Caller()] + e.Unlock() + if !ok { + return xconn.NewInvocationError("wamp.error.unavailable", "unavailable") + } + + p.Lock() + ptmx, ok := p.ptmx[caller] + p.Unlock() + + if !ok { + cmd := exec.Command("bash") + newPtmx, err := pty.Start(cmd) + if err != nil { + return xconn.NewInvocationError("io.xconn.error", err.Error()) + } + + ptmx = newPtmx + p.Lock() + p.ptmx[caller] = newPtmx + p.Unlock() + + go func(inv *xconn.Invocation, ptmx *os.File) { + buf := make([]byte, 4096) + for { + n, err := ptmx.Read(buf) + if n > 0 { + ciphertext, nonce, errEnc := berncrypt.EncryptChaCha20Poly1305(buf[:n], key.Send) + if errEnc != nil { + log.Printf("Encryption failed in shell output: %v", errEnc) + break + } + payload := append(nonce, ciphertext...) + _ = inv.SendProgress([]any{payload}, nil) + } + + if err != nil { + _ = inv.SendProgress(nil, nil) + break + } + } + + }(inv, ptmx) + return xconn.NewInvocationError(xconn.ErrNoResult) + + } + + if inv.Progress() { + payload, err := inv.ArgBytes(0) + if err != nil { + return xconn.NewInvocationError("wamp.error.invalid_argument", err.Error()) + } + if len(payload) < 12 { + return xconn.NewInvocationError("wamp.error.invalid_argument", "payload too short") + } + + decrypted, err := berncrypt.DecryptChaCha20Poly1305(payload[12:], payload[:12], key.Receive) + if err != nil { + ptmx.Close() + return xconn.NewInvocationError("io.xconn.error", err.Error()) + } + + _, _ = ptmx.Write(decrypted) + return xconn.NewInvocationError(xconn.ErrNoResult) + } + + p.Lock() + ptmx, ok = p.ptmx[caller] + delete(p.ptmx, caller) + p.Unlock() + if ok { + ptmx.Close() + } + + return xconn.NewInvocationResult() + } +} + func runCommand(cmd string, args ...string) ([]byte, error) { - var stdout, stderr bytes.Buffer - command := exec.Command(cmd, args...) - command.Stdout = &stdout - command.Stderr = &stderr - err := command.Run() + fullCmd := cmd + if len(args) > 0 { + fullCmd += " " + strings.Join(args, " ") + } + c := exec.Command("bash", "-ic", fullCmd) + ptmx, err := pty.Start(c) if err != nil { - return stderr.Bytes(), err + return nil, err } + defer func() { _ = ptmx.Close() }() + + var stdout bytes.Buffer + _, _ = stdout.ReadFrom(ptmx) + return stdout.Bytes(), nil } @@ -71,7 +173,6 @@ func handleRunCommand(e *wampshell.EncryptionManager) func(_ context.Context, newStrs := strings.Split(s, " ") cmd := newStrs[0] - rawArgs := newStrs[1:] output, err := runCommand(cmd, rawArgs...) @@ -81,7 +182,8 @@ func handleRunCommand(e *wampshell.EncryptionManager) func(_ context.Context, ciphertext1, nonce1, err1 := berncrypt.EncryptChaCha20Poly1305(output, key.Send) if err1 != nil { - panic(err) + log.Printf("Encryption failed in runCommand: %v", err1) + return xconn.NewInvocationError("wamp.error.internal_error", err1.Error()) } payload1 := make([]byte, len(nonce1)+len(ciphertext1)) @@ -95,6 +197,8 @@ func handleRunCommand(e *wampshell.EncryptionManager) func(_ context.Context, func handleFileUpload(e *wampshell.EncryptionManager) func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { return func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { + log.Printf("handleFileUpload called for caller: %d", inv.Caller()) + if len(inv.Args()) < 2 { return xconn.NewInvocationError("wamp.error.invalid_argument", "expected filename + encrypted data") } @@ -139,6 +243,8 @@ func handleFileUpload(e *wampshell.EncryptionManager) func(_ context.Context, func handleFileDownload(e *wampshell.EncryptionManager) func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { return func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { + log.Printf("handleFileDownload called for caller: %d", inv.Caller()) + filename, err := inv.ArgString(0) if err != nil { return xconn.NewInvocationError("wamp.error.invalid_argument", err.Error()) @@ -174,18 +280,7 @@ func registerProcedure(session *xconn.Session, procedure string, handler xconn.I return nil } -type Options struct { -} - func main() { - var opts Options - parser := flags.NewParser(&opts, flags.Default) - - _, err := parser.Parse() - if err != nil { - os.Exit(1) - } - address := fmt.Sprintf("%s:%d", defaultHost, defaultPort) path := os.ExpandEnv("$HOME/.wampshell/authorized_keys") @@ -215,6 +310,7 @@ func main() { name string handler xconn.InvocationHandler }{ + {procedureInteractive, newInteractiveShellSession().handleShell(encryption)}, {procedureExec, handleRunCommand(encryption)}, {procedureFileUpload, handleFileUpload(encryption)}, {procedureFileDownload, handleFileDownload(encryption)}, @@ -252,6 +348,7 @@ func main() { } err = webRtcManager.Setup(cfg) if err != nil { + log.Printf("Failed to setup WebRTC: %v", err) return } diff --git a/go.mod b/go.mod index 65fa92b..0dde3e1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/xconnio/wampshell go 1.24.6 require ( + github.com/creack/pty v1.1.24 github.com/fsnotify/fsnotify v1.9.0 github.com/jessevdk/go-flags v1.6.1 github.com/xconnio/berncrypt/go v0.0.0-20250825151556-89c24973ee7a @@ -10,6 +11,7 @@ require ( github.com/xconnio/wampproto-capnproto/go v0.0.0-20250921183631-6decd38ce372 github.com/xconnio/wampproto-go v0.0.0-20250915142018-1ae321b40fec github.com/xconnio/xconn-go v0.0.0-20250918124058-95e16bcd2454 + golang.org/x/term v0.35.0 ) require ( diff --git a/go.sum b/go.sum index ab7b517..7fd7d34 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ capnproto.org/go/capnp/v3 v3.1.0-alpha.1 h1:8/sMnWuatR99G0L0vmnrXj0zVP0MrlyClRqS capnproto.org/go/capnp/v3 v3.1.0-alpha.1/go.mod h1:2vT5D2dtG8sJGEoEKU17e+j7shdaYp1Myl8X03B3hmc= github.com/colega/zeropool v0.0.0-20230505084239-6fb4a4f75381 h1:d5EKgQfRQvO97jnISfR89AiCCCJMwMFoSxUiU0OGCRU= github.com/colega/zeropool v0.0.0-20230505084239-6fb4a4f75381/go.mod h1:OU76gHeRo8xrzGJU3F3I1CqX1ekM8dfJw0+wPeMwnp0= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -124,6 +126,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From a80119c16c41c5f8d6722998a3b659d00bf196e0 Mon Sep 17 00:00:00 2001 From: asimfarooq5 Date: Sat, 20 Sep 2025 19:57:20 +0500 Subject: [PATCH 2/4] Extract PTY session creation into startPtySession function --- cmd/wshd/main.go | 109 ++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/cmd/wshd/main.go b/cmd/wshd/main.go index 20b91b5..2014532 100644 --- a/cmd/wshd/main.go +++ b/cmd/wshd/main.go @@ -45,6 +45,54 @@ func newInteractiveShellSession() *interactiveShellSession { } } +func (p *interactiveShellSession) startPtySession(caller uint64, inv *xconn.Invocation, sendKey []byte) (*os.File, error) { + cmd := exec.Command("bash") + ptmx, err := pty.Start(cmd) + if err != nil { + return nil, fmt.Errorf("failed to start PTY: %w", err) + } + + p.Lock() + p.ptmx[caller] = ptmx + p.Unlock() + + p.startOutputReader(caller, inv, ptmx, sendKey) + return ptmx, nil +} + +func (p *interactiveShellSession) startOutputReader(caller uint64, inv *xconn.Invocation, ptmx *os.File, sendKey []byte) { + go func() { + defer func() { + p.Lock() + if stored, exists := p.ptmx[caller]; exists && stored == ptmx { + delete(p.ptmx, caller) + } + p.Unlock() + if err := ptmx.Close(); err != nil { + log.Printf("Error closing PTY for caller %d: %v", caller, err) + } + }() + + buf := make([]byte, 4096) + for { + n, err := ptmx.Read(buf) + if n > 0 { + ciphertext, nonce, errEnc := berncrypt.EncryptChaCha20Poly1305(buf[:n], sendKey) + if errEnc != nil { + log.Printf("Encryption failed in shell output for caller %d: %v", caller, errEnc) + return + } + payload := append(nonce, ciphertext...) + _ = inv.SendProgress([]any{payload}, nil) + } + if err != nil { + _ = inv.SendProgress(nil, nil) + return + } + } + }() +} + func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { return func(_ context.Context, inv *xconn.Invocation) *xconn.InvocationResult { @@ -62,40 +110,12 @@ func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) fu p.Unlock() if !ok { - cmd := exec.Command("bash") - newPtmx, err := pty.Start(cmd) + newPtmx, err := p.startPtySession(caller, inv, key.Send) if err != nil { return xconn.NewInvocationError("io.xconn.error", err.Error()) } - ptmx = newPtmx - p.Lock() - p.ptmx[caller] = newPtmx - p.Unlock() - - go func(inv *xconn.Invocation, ptmx *os.File) { - buf := make([]byte, 4096) - for { - n, err := ptmx.Read(buf) - if n > 0 { - ciphertext, nonce, errEnc := berncrypt.EncryptChaCha20Poly1305(buf[:n], key.Send) - if errEnc != nil { - log.Printf("Encryption failed in shell output: %v", errEnc) - break - } - payload := append(nonce, ciphertext...) - _ = inv.SendProgress([]any{payload}, nil) - } - - if err != nil { - _ = inv.SendProgress(nil, nil) - break - } - } - - }(inv, ptmx) return xconn.NewInvocationError(xconn.ErrNoResult) - } if inv.Progress() { @@ -109,11 +129,20 @@ func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) fu decrypted, err := berncrypt.DecryptChaCha20Poly1305(payload[12:], payload[:12], key.Receive) if err != nil { - ptmx.Close() + p.Lock() + if storedPtmx, exists := p.ptmx[caller]; exists { + storedPtmx.Close() + delete(p.ptmx, caller) + } + p.Unlock() return xconn.NewInvocationError("io.xconn.error", err.Error()) } - _, _ = ptmx.Write(decrypted) + _, err = ptmx.Write(decrypted) + if err != nil { + log.Printf("Failed to write to PTY for caller %d: %v", caller, err) + return xconn.NewInvocationError("io.xconn.error", err.Error()) + } return xconn.NewInvocationError(xconn.ErrNoResult) } @@ -130,20 +159,14 @@ func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) fu } func runCommand(cmd string, args ...string) ([]byte, error) { - fullCmd := cmd - if len(args) > 0 { - fullCmd += " " + strings.Join(args, " ") - } - c := exec.Command("bash", "-ic", fullCmd) - ptmx, err := pty.Start(c) + var stdout, stderr bytes.Buffer + command := exec.Command(cmd, args...) + command.Stdout = &stdout + command.Stderr = &stderr + err := command.Run() if err != nil { - return nil, err + return stderr.Bytes(), err } - defer func() { _ = ptmx.Close() }() - - var stdout bytes.Buffer - _, _ = stdout.ReadFrom(ptmx) - return stdout.Bytes(), nil } From 757724ef0706ddbf44e10c43ec826e173510488f Mon Sep 17 00:00:00 2001 From: asimfarooq5 Date: Sat, 20 Sep 2025 20:13:47 +0500 Subject: [PATCH 3/4] refactor: errors --- cmd/wsh/main.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cmd/wsh/main.go b/cmd/wsh/main.go index bc97052..6246821 100644 --- a/cmd/wsh/main.go +++ b/cmd/wsh/main.go @@ -74,9 +74,7 @@ func startInteractiveShell(session *xconn.Session, keys *keyPair) { if err != nil { log.Fatalf("Failed to set raw mode: %s", err) } - defer func(fd int, oldState *term.State) { - _ = term.Restore(fd, oldState) - }(fd, oldState) + defer func() { _ = term.Restore(fd, oldState) }() firstProgress := true @@ -112,7 +110,7 @@ func startInteractiveShell(session *xconn.Session, keys *keyPair) { plain, err := berncrypt.DecryptChaCha20Poly1305(encData[12:], encData[:12], keys.receive) if err != nil { - panic(err) + fmt.Errorf("decryption error: %w", err) } os.Stdout.Write(plain) @@ -130,7 +128,7 @@ func startInteractiveShell(session *xconn.Session, keys *keyPair) { } } -func runCommand(session *xconn.Session, keys *keyPair, args []string) { +func runCommand(session *xconn.Session, keys *keyPair, args []string) error { b := []byte(strings.Join(args, " ")) ciphertext, nonce, err := berncrypt.EncryptChaCha20Poly1305(b, keys.send) @@ -157,6 +155,7 @@ func runCommand(session *xconn.Session, keys *keyPair, args []string) { panic(err) } fmt.Print(string(plain)) + return nil } type Options struct { @@ -208,8 +207,7 @@ func main() { authenticator, err := auth.NewCryptoSignAuthenticator("", privateKey, nil) if err != nil { - fmt.Printf("Error creating crypto sign authenticator: %v", err) - os.Exit(1) + log.Fatal("Error creating crypto sign authenticator:", err) } client := xconn.Client{ From 218b68d3287ff0c29ede0dd46f108795c9333728 Mon Sep 17 00:00:00 2001 From: asimfarooq5 Date: Sat, 20 Sep 2025 20:20:42 +0500 Subject: [PATCH 4/4] make lint happy --- cmd/wsh/main.go | 5 ++--- cmd/wshd/main.go | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/wsh/main.go b/cmd/wsh/main.go index 6246821..2a414af 100644 --- a/cmd/wsh/main.go +++ b/cmd/wsh/main.go @@ -110,7 +110,7 @@ func startInteractiveShell(session *xconn.Session, keys *keyPair) { plain, err := berncrypt.DecryptChaCha20Poly1305(encData[12:], encData[:12], keys.receive) if err != nil { - fmt.Errorf("decryption error: %w", err) + _ = fmt.Errorf("decryption error: %w", err) } os.Stdout.Write(plain) @@ -128,7 +128,7 @@ func startInteractiveShell(session *xconn.Session, keys *keyPair) { } } -func runCommand(session *xconn.Session, keys *keyPair, args []string) error { +func runCommand(session *xconn.Session, keys *keyPair, args []string) { b := []byte(strings.Join(args, " ")) ciphertext, nonce, err := berncrypt.EncryptChaCha20Poly1305(b, keys.send) @@ -155,7 +155,6 @@ func runCommand(session *xconn.Session, keys *keyPair, args []string) error { panic(err) } fmt.Print(string(plain)) - return nil } type Options struct { diff --git a/cmd/wshd/main.go b/cmd/wshd/main.go index 2014532..de335d5 100644 --- a/cmd/wshd/main.go +++ b/cmd/wshd/main.go @@ -45,7 +45,8 @@ func newInteractiveShellSession() *interactiveShellSession { } } -func (p *interactiveShellSession) startPtySession(caller uint64, inv *xconn.Invocation, sendKey []byte) (*os.File, error) { +func (p *interactiveShellSession) startPtySession(caller uint64, + inv *xconn.Invocation, sendKey []byte) (*os.File, error) { cmd := exec.Command("bash") ptmx, err := pty.Start(cmd) if err != nil { @@ -60,7 +61,8 @@ func (p *interactiveShellSession) startPtySession(caller uint64, inv *xconn.Invo return ptmx, nil } -func (p *interactiveShellSession) startOutputReader(caller uint64, inv *xconn.Invocation, ptmx *os.File, sendKey []byte) { +func (p *interactiveShellSession) startOutputReader(caller uint64, + inv *xconn.Invocation, ptmx *os.File, sendKey []byte) { go func() { defer func() { p.Lock() @@ -110,11 +112,10 @@ func (p *interactiveShellSession) handleShell(e *wampshell.EncryptionManager) fu p.Unlock() if !ok { - newPtmx, err := p.startPtySession(caller, inv, key.Send) + _, err := p.startPtySession(caller, inv, key.Send) if err != nil { return xconn.NewInvocationError("io.xconn.error", err.Error()) } - ptmx = newPtmx return xconn.NewInvocationError(xconn.ErrNoResult) }