package ssh import ( "fmt" "os/user" "github.com/AlecAivazis/survey/v2" "github.com/kevinburke/ssh_config" "github.com/sfreiberg/simplessh" "github.com/sirupsen/logrus" ) // HostConfig is a SSH host config. type HostConfig struct { Host string IdentityFile string Port string User string } // GetHostConfig retrieves a ~/.ssh/config config for a host. func GetHostConfig(hostname string, hasIdentityFile bool) (HostConfig, error) { var hostConfig HostConfig var host, sshUser, port, idf string if host = ssh_config.Get(hostname, "Hostname"); host == "" { logrus.Debugf("no hostname found in SSH config, assuming %s", hostname) host = hostname } if sshUser = ssh_config.Get(hostname, "User"); sshUser == "" { systemUser, err := user.Current() if err != nil { return hostConfig, err } username := systemUser.Username logrus.Debugf("no username found in SSH config, assuming %s", username) sshUser = username } if port = ssh_config.Get(hostname, "Port"); port == "" { logrus.Debugf("no port found in SSH config, assuming 22") port = "22" } dummyVal := "~/.ssh/identity" if idf = ssh_config.Get(hostname, "IdentityFile"); (idf == dummyVal || idf == "") && hasIdentityFile { return hostConfig, fmt.Errorf("SSH identity file missing for %s from SSH config", hostname) } hostConfig.Host = host hostConfig.IdentityFile = idf hostConfig.Port = port hostConfig.User = sshUser logrus.Debugf("constructed SSH config %s for %s", hostConfig, hostname) return hostConfig, nil } // New creates a new SSH client connection. func New(domainName, sshAuth string) (*simplessh.Client, error) { var client *simplessh.Client hasIdentityFile := true if sshAuth == "password" { hasIdentityFile = false } hostConfig, err := GetHostConfig(domainName, hasIdentityFile) if err != nil { return client, err } if sshAuth == "identity-file" { var err error client, err = simplessh.ConnectWithAgent(hostConfig.Host, hostConfig.User) if err != nil { return client, err } } else { password := "" prompt := &survey.Password{ Message: "SSH password?", } if err := survey.AskOne(prompt, &password); err != nil { return client, err } var err error client, err = simplessh.ConnectWithPassword(hostConfig.Host, hostConfig.User, password) if err != nil { return client, err } } return client, nil }