Skip to content

Conversation

@asimfarooq5
Copy link
Member

No description provided.

cmd/wshd/main.go Outdated
Comment on lines 67 to 100
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)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can create a separate function for this may be called startPty or startTerminal

cmd/wshd/main.go Outdated
Comment on lines 37 to 148
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)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed in this PR we already have a PR for that

cmd/wsh/main.go Outdated
Comment on lines 78 to 80
defer func(fd int, oldState *term.State) {
_ = term.Restore(fd, oldState)
}(fd, oldState)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
defer func(fd int, oldState *term.State) {
_ = term.Restore(fd, oldState)
}(fd, oldState)
defer func() { _ = term.Restore(fd, oldState)}()

cmd/wsh/main.go Outdated

plain, err := berncrypt.DecryptChaCha20Poly1305(encData[12:], encData[:12], keys.receive)
if err != nil {
panic(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return error instead

cmd/wsh/main.go Outdated
}
}

func runCommand(session *xconn.Session, keys *keyPair, args []string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func runCommand(session *xconn.Session, keys *keyPair, args []string) {
func runCommand(session *xconn.Session, keys *keyPair, args []string) error {

cmd/wsh/main.go Outdated
Comment on lines 211 to 213
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use log.Fatal

@om26er om26er changed the title Implement interactive shell support Implement interactive shell Sep 20, 2025
@om26er om26er force-pushed the feat/interactive-shell branch from ff45169 to 306e1da Compare September 21, 2025 19:16
@om26er om26er force-pushed the feat/interactive-shell branch from 306e1da to 218b68d Compare September 21, 2025 19:29
cmd/wshd/main.go Outdated
p.ptmx[caller] = ptmx
p.Unlock()

p.startOutputReader(caller, inv, ptmx, sendKey)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
p.startOutputReader(caller, inv, ptmx, sendKey)
go p.startOutputReader(inv, ptmx, sendKey)

and then we can remove the go routine inside the function

cmd/wshd/main.go Outdated
Comment on lines 64 to 96
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
}
}
}()
}
Copy link
Member

@muzzammilshahid muzzammilshahid Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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) startOutputReader(inv *xconn.Invocation, ptmx *os.File, sendKey []byte) {
caller := inv.Caller()
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
}
}
}

cmd/wshd/main.go Outdated
Comment on lines 48 to 58
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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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()
func (p *interactiveShellSession) startPtySession(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[inv.Caller()] = ptmx
p.Unlock()

@asimfarooq5 asimfarooq5 changed the title Implement interactive shell refactor: Suggested changes Sep 23, 2025
@asimfarooq5 asimfarooq5 changed the title refactor: Suggested changes Implement interactive shell Sep 23, 2025
cmd/wshd/main.go Outdated
Comment on lines 67 to 69
if stored, exists := p.ptmx[caller]; exists && stored == ptmx {
delete(p.ptmx, caller)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if stored, exists := p.ptmx[caller]; exists && stored == ptmx {
delete(p.ptmx, caller)
}
delete(p.ptmx, caller)

cmd/wshd/main.go Outdated
}

p.Lock()
ptmx, ok = p.ptmx[caller]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ptmx, ok = p.ptmx[caller]

cmd/wsh/main.go Outdated
}, nil
}

func startInteractiveShell(session *xconn.Session, keys *keyPair) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func startInteractiveShell(session *xconn.Session, keys *keyPair) {
func startInteractiveShell(session *xconn.Session, keys *keyPair) error {

and change function accordingly

cmd/wsh/main.go Outdated
}
}

func runCommand(session *xconn.Session, keys *keyPair, args []string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func runCommand(session *xconn.Session, keys *keyPair, args []string) {
func runCommand(session *xconn.Session, keys *keyPair, args []string) error {

and change function accordingly

@om26er om26er merged commit 3e45ca3 into main Sep 23, 2025
1 check passed
@om26er om26er deleted the feat/interactive-shell branch September 23, 2025 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants