From 3fc19adefa27cf169717336a6e67340673ab4e78 Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Sun, 2 Aug 2020 19:52:24 -0700 Subject: [PATCH] Add host key flag to SSH server --- Dockerfile | 5 ++-- Makefile | 3 +++ README.md | 8 ++++++- cmd/cointop.go | 5 +++- cointop/cointop.go | 3 ++- cointop/common/pathutil/pathutil.go | 37 +++++++++++++++++++++++++++++ cointop/config.go | 9 +++---- cointop/ssh/server.go | 25 ++++++++++++------- cointop/util.go | 32 ------------------------- 9 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 cointop/common/pathutil/pathutil.go diff --git a/Dockerfile b/Dockerfile index 41337a4..7440ed3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:latest +FROM golang:1.14 RUN mkdir /app WORKDIR /app @@ -7,4 +7,5 @@ ADD . /app/ RUN go build -o main . RUN mv main /bin/cointop -CMD cointop +ENTRYPOINT cointop +CMD [] diff --git a/Makefile b/Makefile index 71eaea3..434ed47 100644 --- a/Makefile +++ b/Makefile @@ -195,3 +195,6 @@ docker-run: docker-push: docker push cointop/cointop:latest + +docker-run-ssh: + docker run -p 2222:22 -v ~/.ssh/demo:/keys --entrypoint cointop -it cointop/cointop server -k /keys/id_rsa diff --git a/README.md b/README.md index 9d47ea5..60c7ef5 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ There are multiple ways you can install cointop depending on the platform you're Make sure to have [go](https://golang.org/) (1.12+) installed, then do: ```bash -go get -u github.com/miguelmota/cointop +go get github.com/miguelmota/cointop ``` Make sure `$GOPATH/bin` is added to the `$PATH` variable. @@ -599,6 +599,12 @@ SSH demo: ssh cointop.sh ``` +Using docker to run SSH server: + +```bash +docker run -p 2222:22 -v ~/.ssh:/keys --entrypoint cointop -it cointop/cointop server -k /keys/id_rsa +``` + ## FAQ Frequently asked questions: diff --git a/cmd/cointop.go b/cmd/cointop.go index d50f9b9..7e2fdf8 100644 --- a/cmd/cointop.go +++ b/cmd/cointop.go @@ -171,6 +171,7 @@ For more information, visit: https://github.com/miguelmota/cointop`, var address string = "0.0.0.0" var idleTimeout uint = 60 var executableBinary string = "cointop" + var hostKeyFile string = cssh.DefaultHostKeyFile serverCmd := &cobra.Command{ Use: "server", @@ -182,6 +183,7 @@ For more information, visit: https://github.com/miguelmota/cointop`, Port: port, IdleTimeout: time.Duration(int(idleTimeout)) * time.Second, ExecutableBinary: executableBinary, + HostKeyFile: hostKeyFile, }) fmt.Printf("Running SSH server on port %v\n", port) @@ -192,7 +194,8 @@ For more information, visit: https://github.com/miguelmota/cointop`, serverCmd.Flags().UintVarP(&port, "port", "p", port, "Port") serverCmd.Flags().StringVarP(&address, "address", "a", address, "Address") serverCmd.Flags().UintVarP(&idleTimeout, "idle-timeout", "t", idleTimeout, "Idle timeout in seconds") - serverCmd.Flags().StringVarP(&executableBinary, "binary", "b", executableBinary, "ExecutableBinary") + serverCmd.Flags().StringVarP(&executableBinary, "binary", "b", executableBinary, "Executable binary path") + serverCmd.Flags().StringVarP(&hostKeyFile, "host-key-file", "k", hostKeyFile, "Host key file") rootCmd.AddCommand(versionCmd, cleanCmd, resetCmd, priceCmd, testCmd, serverCmd) diff --git a/cointop/cointop.go b/cointop/cointop.go index 7dca722..76aa045 100644 --- a/cointop/cointop.go +++ b/cointop/cointop.go @@ -14,6 +14,7 @@ import ( "github.com/miguelmota/cointop/cointop/common/filecache" "github.com/miguelmota/cointop/cointop/common/gizak/termui" "github.com/miguelmota/cointop/cointop/common/humanize" + "github.com/miguelmota/cointop/cointop/common/pathutil" "github.com/miguelmota/cointop/cointop/common/table" "github.com/miguelmota/gocui" "github.com/patrickmn/go-cache" @@ -467,7 +468,7 @@ func Reset(config *ResetConfig) error { } // default config path - configPath := fmt.Sprintf("%s%s", UserPreferredHomeDir(), "/.cointop") + configPath := fmt.Sprintf("%s%s", pathutil.UserPreferredHomeDir(), "/.cointop") if _, err := os.Stat(configPath); !os.IsNotExist(err) { if config.Log { fmt.Printf("removing %s\n", configPath) diff --git a/cointop/common/pathutil/pathutil.go b/cointop/common/pathutil/pathutil.go new file mode 100644 index 0000000..def97a9 --- /dev/null +++ b/cointop/common/pathutil/pathutil.go @@ -0,0 +1,37 @@ +package pathutil + +import ( + "os" + "path/filepath" + "runtime" + "strings" +) + +// UserPreferredHomeDir returns the preferred home directory for the user +func UserPreferredHomeDir() string { + var home string + + if runtime.GOOS == "windows" { + home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + } else if runtime.GOOS == "linux" { + home = os.Getenv("XDG_CONFIG_HOME") + } + + if home == "" { + home, _ = os.UserHomeDir() + } + + return home +} + +// NormalizePath normalizes and extends the path string +func NormalizePath(path string) string { + // expand tilde + if strings.HasPrefix(path, "~/") { + path = filepath.Join(UserPreferredHomeDir(), path[2:]) + } + + path = strings.Replace(path, "/", string(filepath.Separator), -1) + + return path +} diff --git a/cointop/config.go b/cointop/config.go index 8b55ae6..4855267 100644 --- a/cointop/config.go +++ b/cointop/config.go @@ -10,6 +10,7 @@ import ( "time" "github.com/BurntSushi/toml" + "github.com/miguelmota/cointop/cointop/common/pathutil" ) var fileperm = os.FileMode(0644) @@ -77,7 +78,7 @@ func (ct *Cointop) CreateConfigIfNotExists() error { } for _, previousConfigFilepath := range previousDefaultConfigPaths { - normalizedPath := NormalizePath(previousConfigFilepath) + normalizedPath := pathutil.NormalizePath(previousConfigFilepath) if _, err := os.Stat(normalizedPath); err == nil { ct.configFilepath = normalizedPath return nil @@ -100,7 +101,7 @@ func (ct *Cointop) CreateConfigIfNotExists() error { // ConfigDirPath returns the config directory path func (ct *Cointop) ConfigDirPath() string { ct.debuglog("configDirPath()") - path := NormalizePath(ct.configFilepath) + path := pathutil.NormalizePath(ct.configFilepath) separator := string(filepath.Separator) parts := strings.Split(path, separator) return strings.Join(parts[0:len(parts)-1], separator) @@ -109,7 +110,7 @@ func (ct *Cointop) ConfigDirPath() string { // ConfigFilePath return the config file path func (ct *Cointop) ConfigFilePath() string { ct.debuglog("configFilePath()") - return NormalizePath(ct.configFilepath) + return pathutil.NormalizePath(ct.configFilepath) } // ConfigPath return the config file path @@ -331,7 +332,7 @@ func (ct *Cointop) getColorschemeColors() (map[string]interface{}, error) { return nil, err } } else { - path := NormalizePath(fmt.Sprintf("~/.cointop/colors/%s.toml", ct.colorschemeName)) + path := pathutil.NormalizePath(fmt.Sprintf("~/.cointop/colors/%s.toml", ct.colorschemeName)) if _, err := os.Stat(path); os.IsNotExist(err) { // NOTE: case for when cointop is set as the theme but the colorscheme file doesn't exist if ct.colorschemeName == "cointop" { diff --git a/cointop/ssh/server.go b/cointop/ssh/server.go index d153b01..431192e 100644 --- a/cointop/ssh/server.go +++ b/cointop/ssh/server.go @@ -10,22 +10,26 @@ import ( "io/ioutil" "os" "os/exec" - "path" "syscall" "time" "unsafe" "github.com/creack/pty" "github.com/gliderlabs/ssh" + "github.com/miguelmota/cointop/cointop/common/pathutil" gossh "golang.org/x/crypto/ssh" ) +// DefaultHostKeyFile ... +var DefaultHostKeyFile = "~/.ssh/id_rsa" + // Config ... type Config struct { Port uint Address string IdleTimeout time.Duration ExecutableBinary string + HostKeyFile string } // Server ... @@ -35,25 +39,29 @@ type Server struct { idleTimeout time.Duration executableBinary string sshServer *ssh.Server + hostKeyFile string } // NewServer ... func NewServer(config *Config) *Server { + hostKeyFile := DefaultHostKeyFile + if config.HostKeyFile != "" { + hostKeyFile = config.HostKeyFile + } + + hostKeyFile = pathutil.NormalizePath(hostKeyFile) + return &Server{ port: config.Port, address: config.Address, idleTimeout: config.IdleTimeout, executableBinary: config.ExecutableBinary, + hostKeyFile: hostKeyFile, } } // ListenAndServe ... func (s *Server) ListenAndServe() error { - homeDir, err := os.UserHomeDir() - if err != nil { - return err - } - s.sshServer = &ssh.Server{ Addr: fmt.Sprintf("%s:%v", s.address, s.port), IdleTimeout: s.idleTimeout, @@ -116,12 +124,11 @@ func (s *Server) ListenAndServe() error { }, } - hostKeyFile := path.Join(homeDir, ".ssh", "id_rsa") - if _, err := os.Stat(hostKeyFile); os.IsNotExist(err) { + if _, err := os.Stat(s.hostKeyFile); os.IsNotExist(err) { return errors.New("SSH key is required to start server") } - err = s.sshServer.SetOption(ssh.HostKeyFile(hostKeyFile)) + err := s.sshServer.SetOption(ssh.HostKeyFile(s.hostKeyFile)) if err != nil { return err } diff --git a/cointop/util.go b/cointop/util.go index 90d409c..33506b3 100644 --- a/cointop/util.go +++ b/cointop/util.go @@ -3,9 +3,6 @@ package cointop import ( "bytes" "encoding/gob" - "os" - "path/filepath" - "runtime" "strings" "github.com/miguelmota/cointop/cointop/common/open" @@ -29,35 +26,6 @@ func GetBytes(key interface{}) ([]byte, error) { return buf.Bytes(), nil } -// UserPreferredHomeDir returns the preferred home directory for the user -func UserPreferredHomeDir() string { - var home string - - if runtime.GOOS == "windows" { - home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - } else if runtime.GOOS == "linux" { - home = os.Getenv("XDG_CONFIG_HOME") - } - - if home == "" { - home, _ = os.UserHomeDir() - } - - return home -} - -// NormalizePath normalizes and extends the path string -func NormalizePath(path string) string { - // expand tilde - if strings.HasPrefix(path, "~/") { - path = filepath.Join(UserPreferredHomeDir(), path[2:]) - } - - path = strings.Replace(path, "/", string(filepath.Separator), -1) - - return path -} - // Slugify returns a slugified string func Slugify(s string) string { s = strings.TrimSpace(strings.ToLower(s))