From dafa1fce5d40d3abcb533db6af8f0541ec34f0ec Mon Sep 17 00:00:00 2001 From: Illyoung Choi Date: Fri, 15 Nov 2024 12:01:52 -0700 Subject: [PATCH] Fix password input bug --- cmd/commons/args.go | 17 ++------- cmd/main.go | 56 ++++++++++------------------- commons/input.go | 86 ++++++++++++++++++++++++++++++++++++++++++++ commons/print.go | 87 +++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 6 ++++ utils/fuse.go | 24 +++++++++++++ 7 files changed, 226 insertions(+), 52 deletions(-) create mode 100644 commons/input.go create mode 100644 commons/print.go diff --git a/cmd/commons/args.go b/cmd/commons/args.go index 3d4fd91..205f85d 100644 --- a/cmd/commons/args.go +++ b/cmd/commons/args.go @@ -8,10 +8,8 @@ import ( "path/filepath" "strconv" "strings" - "syscall" "github.com/cyverse/irodsfs/commons" - "golang.org/x/term" "golang.org/x/xerrors" "gopkg.in/natefinch/lumberjack.v2" @@ -203,7 +201,6 @@ func ProcessCommonFlags(command *cobra.Command, args []string) (*commons.Config, // overwrite config config = newConfig - stdinClosed = true } if len(config.LogLevel) > 0 { @@ -533,7 +530,7 @@ func PrintVersion(command *cobra.Command) error { return err } - fmt.Println(info) + commons.Println(info) return nil } @@ -566,8 +563,7 @@ func getLogWriterForChildProcess(logPath string) (io.WriteCloser, string) { // inputMissingParams gets user inputs for parameters missing, such as username and password func inputMissingParams(config *commons.Config) error { if len(config.Username) == 0 { - fmt.Print("Username: ") - fmt.Scanln(&config.Username) + config.Username = commons.Input("Username: ") } if len(config.ClientUsername) == 0 { @@ -575,14 +571,7 @@ func inputMissingParams(config *commons.Config) error { } if len(config.Password) == 0 { - fmt.Print("Password: ") - bytePassword, err := term.ReadPassword(int(syscall.Stdin)) - fmt.Print("\n") - if err != nil { - return xerrors.Errorf("failed to read password: %w", err) - } - - config.Password = string(bytePassword) + config.Password = commons.InputPassword("iRODS Password") } config.FixAuthConfiguration() diff --git a/cmd/main.go b/cmd/main.go index 6a0a8aa..ae669a1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -43,21 +43,23 @@ func processCommand(command *cobra.Command, args []string) error { if cmd_commons.IsChildProcess(command) { // child process childMain() - } else { - // parent process - parentMain(command, args) + return nil } - return nil + // parent process + return parentMain(command, args) } func main() { + commons.InitTerminalOutput() + log.SetFormatter(&log.TextFormatter{ TimestampFormat: "2006-01-02 15:04:05.000000", FullTimestamp: true, }) log.SetLevel(log.InfoLevel) + log.SetOutput(commons.GetTerminalWriter()) logger := log.WithFields(log.Fields{ "package": "main", @@ -69,73 +71,53 @@ func main() { err := Execute() if err != nil { - logger.Fatalf("%+v", err) + logger.Errorf("%+v", err) + commons.PrintErrorf("%+v\n", err) os.Exit(1) } } // parentMain handles command-line parameters and run parent process -func parentMain(command *cobra.Command, args []string) { - logger := log.WithFields(log.Fields{ - "package": "main", - "function": "parentMain", - }) - +func parentMain(command *cobra.Command, args []string) error { config, logWriter, cont, err := cmd_commons.ProcessCommonFlags(command, args) if logWriter != nil { defer logWriter.Close() } if err != nil { - logger.Errorf("%+v", err) - os.Exit(1) + return err } if !cont { - os.Exit(0) + return nil } // check fuse - fuseCheckResult := utils.CheckFuse() - switch fuseCheckResult { - case utils.CheckFUSEStatusFound: - // okay - logger.Info("Found FUSE Device. Starting iRODS FUSE Lite.") - case utils.CheckFUSEStatusUnknown: - // try to go - logger.Info("It is not sure whether FUSE is running. Starting iRODS FUSE Lite, anyway.") - case utils.CheckFUSEStatusNotFound: - logger.Error("FUSE is not running. Terminating iRODS FUSE Lite.") - os.Exit(1) - case utils.CheckFUSEStatusCannotRun: - logger.Error("FUSE is not supported. Terminating iRODS FUSE Lite.") - os.Exit(1) + err = utils.EnsureFuse() + if err != nil { + return err } if !config.Foreground { // background childStdin, childStdout, err := cmd_commons.RunChildProcess(os.Args[0]) if err != nil { - childErr := xerrors.Errorf("failed to run iRODS FUSE Lite child process: %w", err) - logger.Errorf("%+v", childErr) - os.Exit(1) + return xerrors.Errorf("failed to run iRODS FUSE Lite child process: %w", err) } err = cmd_commons.ParentProcessSendConfigViaSTDIN(config, childStdin, childStdout) if err != nil { - sendErr := xerrors.Errorf("failed to send configuration to iRODS FUSE Lite child process: %w", err) - logger.Errorf("%+v", sendErr) - os.Exit(1) + return xerrors.Errorf("failed to send configuration to iRODS FUSE Lite child process: %w", err) } } else { // run foreground err = run(config, false) if err != nil { - runErr := xerrors.Errorf("failed to run iRODS FUSE Lite: %w", err) - logger.Errorf("%+v", runErr) - os.Exit(1) + return xerrors.Errorf("failed to run iRODS FUSE Lite: %w", err) } } + + return nil } // childMain runs child process diff --git a/commons/input.go b/commons/input.go new file mode 100644 index 0000000..0c23b0f --- /dev/null +++ b/commons/input.go @@ -0,0 +1,86 @@ +package commons + +import ( + "fmt" + "strconv" + "strings" + "syscall" + + "golang.org/x/term" +) + +var ( + selectedAll bool = false +) + +func Input(msg string) string { + terminalWriter := GetTerminalWriter() + + terminalWriter.Lock() + defer terminalWriter.Unlock() + + red := "\033[31m" + reset := "\033[0m" + + fmt.Printf("%s%s: %s", red, msg, reset) + + userInput := "" + fmt.Scanln(&userInput) + + return userInput +} + +// InputYN inputs Y or N +// true for Y, false for N +func InputYN(msg string) bool { + if selectedAll { + return true + } + + for { + inputString := Input(fmt.Sprintf("%s [yes(y)/no(n)/all(a)]", msg)) + inputString = strings.ToLower(inputString) + if inputString == "y" || inputString == "yes" || inputString == "true" { + return true + } else if inputString == "n" || inputString == "no" || inputString == "false" { + return false + } else if inputString == "a" || inputString == "all" { + selectedAll = true + return true + } + } +} + +func InputInt(msg string) int { + inputString := Input(msg) + if len(inputString) == 0 { + return 0 + } + + v, err := strconv.Atoi(inputString) + if err != nil { + return 0 + } + + return v +} + +func InputPassword(msg string) string { + terminalWriter := GetTerminalWriter() + + terminalWriter.Lock() + defer terminalWriter.Unlock() + + red := "\033[31m" + reset := "\033[0m" + + fmt.Printf("%s%s: %s", red, msg, reset) + bytePassword, err := term.ReadPassword(int(syscall.Stdin)) + fmt.Print("\n") + + if err != nil { + return "" + } + + return string(bytePassword) +} diff --git a/commons/print.go b/commons/print.go new file mode 100644 index 0000000..a9bc9b4 --- /dev/null +++ b/commons/print.go @@ -0,0 +1,87 @@ +package commons + +import ( + "fmt" + "io" + "os" + "sync" + + log "github.com/sirupsen/logrus" +) + +var ( + terminalOutput *TerminalWriter +) + +type TerminalWriter struct { + mutex sync.Mutex +} + +func (writer *TerminalWriter) Write(p []byte) (n int, err error) { + writer.mutex.Lock() + defer writer.mutex.Unlock() + return os.Stdout.Write(p) +} + +func (writer *TerminalWriter) Lock() { + writer.mutex.Lock() +} + +func (writer *TerminalWriter) Unlock() { + writer.mutex.Unlock() +} + +func InitTerminalOutput() { + terminalOutput = &TerminalWriter{} +} + +func GetTerminalWriter() *TerminalWriter { + return terminalOutput +} + +func PrintInfoln(a ...any) (n int, err error) { + if log.GetLevel() > log.InfoLevel { + return Println(a...) + } + return 0, nil +} + +func PrintInfof(format string, a ...any) (n int, err error) { + if log.GetLevel() > log.InfoLevel { + return Printf(format, a...) + } + return 0, nil +} + +func Print(a ...any) (n int, err error) { + return fmt.Fprint(terminalOutput, a...) +} + +func Printf(format string, a ...any) (n int, err error) { + return fmt.Fprintf(terminalOutput, format, a...) +} + +func Println(a ...any) (n int, err error) { + return fmt.Fprintln(terminalOutput, a...) +} + +func Fprintf(w io.Writer, format string, a ...any) (int, error) { + terminalOutput.Lock() + defer terminalOutput.Unlock() + + return fmt.Fprintf(w, format, a...) +} + +func PrintErrorf(format string, a ...any) (int, error) { + terminalOutput.Lock() + defer terminalOutput.Unlock() + + red := "\033[31m" + reset := "\033[0m" + + fmt.Fprint(os.Stderr, red) + n, err := fmt.Fprintf(os.Stderr, format, a...) + fmt.Fprint(os.Stderr, reset) + + return n, err +} diff --git a/go.mod b/go.mod index b0b8f3c..797fa38 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cyverse/irodsfs -go 1.18 +go 1.21 require ( github.com/cyverse/go-irodsclient v0.15.6 diff --git a/go.sum b/go.sum index 73f4f66..559996e 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/hanwen/go-fuse/v2 v2.6.2 h1:Lm0ZDfKYCvdh9pGSv+l4YpuMeR+Q87ArPWh6hWpRPPQ= @@ -34,11 +35,15 @@ github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= @@ -83,6 +88,7 @@ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cn google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/utils/fuse.go b/utils/fuse.go index 77d2af3..664e804 100644 --- a/utils/fuse.go +++ b/utils/fuse.go @@ -61,6 +61,30 @@ func CheckDevFuse() CheckFUSEStatus { return CheckFUSEStatusUnknown } +// EnsureFuse raise error if fuse is not found +func EnsureFuse() error { + logger := log.WithFields(log.Fields{ + "package": "utils", + "function": "EnsureFuse", + }) + + fuseCheckResult := CheckFuse() + switch fuseCheckResult { + case CheckFUSEStatusFound: + // okay + logger.Info("Found FUSE Device.") + case CheckFUSEStatusUnknown: + // try to go + logger.Info("It is not sure whether FUSE is running. Continue...") + case CheckFUSEStatusNotFound: + return xerrors.Errorf("FUSE is not running.") + case CheckFUSEStatusCannotRun: + return xerrors.Errorf("FUSE is not supported.") + } + + return nil +} + // Unmount calls fusermount -uz on the mount. func UnmountFuse(mountPoint string) (err error) { bin, err := fusermountBinary()