-
Notifications
You must be signed in to change notification settings - Fork 0
Implement interactive shell #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
cmd/wshd/main.go
Outdated
| 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) | ||
|
|
There was a problem hiding this comment.
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
| 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) | ||
|
|
There was a problem hiding this comment.
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
| defer func(fd int, oldState *term.State) { | ||
| _ = term.Restore(fd, oldState) | ||
| }(fd, oldState) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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) |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| func runCommand(session *xconn.Session, keys *keyPair, args []string) { | |
| func runCommand(session *xconn.Session, keys *keyPair, args []string) error { |
cmd/wsh/main.go
Outdated
| 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) |
There was a problem hiding this comment.
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
ff45169 to
306e1da
Compare
306e1da to
218b68d
Compare
cmd/wshd/main.go
Outdated
| p.ptmx[caller] = ptmx | ||
| p.Unlock() | ||
|
|
||
| p.startOutputReader(caller, inv, ptmx, sendKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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
| 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 | ||
| } | ||
| } | ||
| }() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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
| 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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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() |
cmd/wshd/main.go
Outdated
| if stored, exists := p.ptmx[caller]; exists && stored == ptmx { | ||
| delete(p.ptmx, caller) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ptmx, ok = p.ptmx[caller] |
cmd/wsh/main.go
Outdated
| }, nil | ||
| } | ||
|
|
||
| func startInteractiveShell(session *xconn.Session, keys *keyPair) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| func runCommand(session *xconn.Session, keys *keyPair, args []string) { | |
| func runCommand(session *xconn.Session, keys *keyPair, args []string) error { |
and change function accordingly
No description provided.