diff --git a/cmd/virtual-serve.go b/cmd/virtual-serve.go index 25918f1..f0da41f 100644 --- a/cmd/virtual-serve.go +++ b/cmd/virtual-serve.go @@ -3,8 +3,11 @@ package cmd import ( + "bufio" "fmt" + "io" "os" + "strings" "github.com/beevik/guid" "github.com/blang/semver/v4" @@ -13,6 +16,7 @@ import ( "github.com/loophole/cli/internal/pkg/apiclient" "github.com/loophole/cli/internal/pkg/cache" "github.com/loophole/cli/internal/pkg/communication" + "github.com/loophole/cli/internal/pkg/inpututil" "github.com/spf13/cobra" "github.com/spf13/pflag" "golang.org/x/crypto/ssh/terminal" @@ -56,14 +60,29 @@ func parseBasicAuthFlags(flagset *pflag.FlagSet) error { }) if usernameProvided && !passwordProvided { - fmt.Print("Enter basic auth password: ") + var password string + if !inpututil.IsUsingPipe() { //only ask for password in terminal if not using pipe + fmt.Print("Enter basic auth password: ") + var err error + passwordBytes, err := terminal.ReadPassword(int(os.Stdin.Fd())) + password = string(passwordBytes) + if err != nil { + return err + } + fmt.Println() + } else { + reader := bufio.NewReader(os.Stdin) + passwordBytes, err := reader.ReadBytes('\n') + //if the reader encounters EOF before \n, + //we assume that everything up until EOF is the intended password and continue + if err != nil && err != io.EOF { + communication.Warn("An error occured while reading the basic auth password from pipe.") + communication.Fatal(err.Error()) + } + password = strings.TrimSuffix(string(passwordBytes), "\n") - password, err := terminal.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - return err } - fmt.Println() - passwordFlag.Value.Set(string(password)) + passwordFlag.Value.Set(password) } if passwordProvided && !usernameProvided { return fmt.Errorf("When using basic auth, both %s and %s have to be provided", basicAuthUsernameFlagName, basicAuthPasswordFlagName) diff --git a/internal/pkg/closehandler/closehandler.go b/internal/pkg/closehandler/closehandler.go index 803273c..86e60d4 100644 --- a/internal/pkg/closehandler/closehandler.go +++ b/internal/pkg/closehandler/closehandler.go @@ -6,6 +6,7 @@ import ( "syscall" "github.com/loophole/cli/internal/pkg/communication" + "github.com/loophole/cli/internal/pkg/inpututil" "golang.org/x/crypto/ssh/terminal" ) @@ -14,14 +15,18 @@ var terminalState *terminal.State = &terminal.State{} // SetupCloseHandler ensures that CTRL+C inputs are properly processed, restoring the terminal state from not displaying entered characters where necessary func SetupCloseHandler(feedbackFormURL string) { + var terminalState *terminal.State c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) - terminalState, err := terminal.GetState(int(os.Stdin.Fd())) - if err != nil { - communication.Warn("Error saving terminal state") - communication.Warn(err.Error()) - } + if !inpututil.IsUsingPipe() { //don't try to get terminal state if using a pipe + var err error + terminalState, err = terminal.GetState(int(os.Stdin.Fd())) + if err != nil { + communication.Warn("Error saving terminal state") + communication.Fatal(err.Error()) + } + } go func() { <-c if terminalState != nil { diff --git a/internal/pkg/inpututil/inpututil.go b/internal/pkg/inpututil/inpututil.go new file mode 100644 index 0000000..82f7e94 --- /dev/null +++ b/internal/pkg/inpututil/inpututil.go @@ -0,0 +1,17 @@ +package inpututil + +import ( + "os" + + "github.com/loophole/cli/internal/pkg/communication" +) + +//IsUsingPipe returns whether a pipe is being used for inputs or not +func IsUsingPipe() bool { + stdinInfo, err := os.Stdin.Stat() + if err != nil { + communication.Warn("Error getting terminal info") + communication.Fatal(err.Error()) + } + return (stdinInfo.Mode() & os.ModeCharDevice) == 0 +}