123 lines
2.2 KiB
Go
123 lines
2.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"net"
|
||
|
"net/url"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
expect "github.com/google/goexpect"
|
||
|
"golang.org/x/crypto/ssh"
|
||
|
"golang.org/x/crypto/ssh/agent"
|
||
|
"golang.org/x/crypto/ssh/terminal"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
timeout = 10 * time.Minute
|
||
|
)
|
||
|
|
||
|
func hostNameCheck(u *url.URL) ssh.PublicKey {
|
||
|
var key ssh.PublicKey
|
||
|
var toMatch string
|
||
|
|
||
|
if strings.Contains(u.Host, ":") {
|
||
|
parts := strings.Split(u.Host, ":")
|
||
|
toMatch = fmt.Sprintf("[%s]:%s", parts[0], parts[1])
|
||
|
} else {
|
||
|
toMatch = u.Host
|
||
|
}
|
||
|
|
||
|
kh, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
defer kh.Close()
|
||
|
|
||
|
scanner := bufio.NewScanner(kh)
|
||
|
for scanner.Scan() {
|
||
|
if strings.Contains(scanner.Text(), toMatch) {
|
||
|
key, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return key
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
|
||
|
if len(os.Args) == 1 {
|
||
|
log.Fatalf("typie: ssh://user@host:port")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
u, err := url.Parse(os.Args[1])
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
socket := os.Getenv("SSH_AUTH_SOCK")
|
||
|
conn, err := net.Dial("unix", socket)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to open SSH_AUTH_SOCK: %v", err)
|
||
|
}
|
||
|
|
||
|
agentClient := agent.NewClient(conn)
|
||
|
config := &ssh.ClientConfig{
|
||
|
User: u.User.String(),
|
||
|
Auth: []ssh.AuthMethod{
|
||
|
ssh.PublicKeysCallback(agentClient.Signers),
|
||
|
},
|
||
|
HostKeyCallback: ssh.FixedHostKey(hostNameCheck(u)),
|
||
|
}
|
||
|
|
||
|
fmt.Print("Password to send: ")
|
||
|
b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
pass := string(b)
|
||
|
fmt.Println()
|
||
|
|
||
|
sshClient, err := ssh.Dial("tcp", u.Host, config)
|
||
|
if err != nil {
|
||
|
log.Fatalf("ssh.Dial(%q) failed: %v", u.Host, err)
|
||
|
}
|
||
|
defer sshClient.Close()
|
||
|
|
||
|
e, _, err := expect.SpawnSSH(sshClient, timeout)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
defer e.Close()
|
||
|
|
||
|
fmt.Print("Watching...")
|
||
|
for {
|
||
|
_, err := e.ExpectBatch([]expect.Batcher{
|
||
|
&expect.BExp{R: "Passphrase: "},
|
||
|
&expect.BSnd{S: fmt.Sprintf("%s\n", pass)},
|
||
|
&expect.BExp{R: "boot>"},
|
||
|
&expect.BSnd{S: "\n"},
|
||
|
}, timeout)
|
||
|
|
||
|
if err != nil {
|
||
|
if err == expect.TimeoutError(timeout) {
|
||
|
// Hi our timeout
|
||
|
fmt.Print(".")
|
||
|
} else {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
time.Sleep(3)
|
||
|
}
|
||
|
}
|