mirror of
https://github.com/BishopFox/sliver
synced 2026-06-08 10:29:05 +00:00
77 lines
1.7 KiB
Go
77 lines
1.7 KiB
Go
package forms
|
|
|
|
import (
|
|
"os"
|
|
|
|
tea "charm.land/bubbletea/v2"
|
|
"charm.land/huh/v2"
|
|
"github.com/bishopfox/sliver/client/termio"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
var openFormTTY = tea.OpenTTY
|
|
|
|
func runForm(form *huh.Form) error {
|
|
cleanup := configureFormTTY(form)
|
|
if cleanup != nil {
|
|
defer cleanup()
|
|
}
|
|
return form.Run()
|
|
}
|
|
|
|
// Console logging swaps stdout/stderr to pipes so the session can be tee'd to
|
|
// disk. Bubble Tea forms need a real TTY output, so temporarily bind them back
|
|
// to the controlling terminal when the interactive console has piped stdio.
|
|
func configureFormTTY(form *huh.Form) func() {
|
|
if form == nil {
|
|
return nil
|
|
}
|
|
|
|
stdinTTY := isTTY(os.Stdin)
|
|
stdoutTTY := isTTY(os.Stdout)
|
|
stderrTTY := isTTY(os.Stderr)
|
|
|
|
switch {
|
|
case shouldUseStdoutTTYForForm(stdinTTY, stdoutTTY, stderrTTY):
|
|
form.WithInput(os.Stdin)
|
|
form.WithOutput(os.Stdout)
|
|
return nil
|
|
|
|
case needsDedicatedTTYForForm(stdinTTY, stdoutTTY, stderrTTY):
|
|
if isTTY(termio.InteractiveInput()) && isTTY(termio.InteractiveOutput()) {
|
|
form.WithInput(termio.InteractiveInput())
|
|
form.WithOutput(termio.InteractiveOutput())
|
|
return nil
|
|
}
|
|
|
|
inTTY, outTTY, err := openFormTTY()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
form.WithInput(inTTY)
|
|
form.WithOutput(outTTY)
|
|
return func() {
|
|
_ = inTTY.Close()
|
|
if outTTY != inTTY {
|
|
_ = outTTY.Close()
|
|
}
|
|
}
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func isTTY(file *os.File) bool {
|
|
return file != nil && term.IsTerminal(int(file.Fd()))
|
|
}
|
|
|
|
func shouldUseStdoutTTYForForm(stdinTTY, stdoutTTY, stderrTTY bool) bool {
|
|
return stdinTTY && stdoutTTY && !stderrTTY
|
|
}
|
|
|
|
func needsDedicatedTTYForForm(stdinTTY, stdoutTTY, stderrTTY bool) bool {
|
|
return stdinTTY && !stdoutTTY && !stderrTTY
|
|
}
|