/
ssh.go
102 lines (89 loc) · 2.3 KB
/
ssh.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package cmd
import (
"fmt"
"io/ioutil"
"os"
"time"
"golang.org/x/crypto/ssh"
"golang.org/x/term"
)
// SSHClient opens a interactive ssh session to the host on port with user, authenticated by the key.
func SSHClient(user, keyfile, host string, port int) error {
publicKeyAuthMethod, err := publicKey(keyfile)
if err != nil {
return err
}
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
publicKeyAuthMethod,
},
//nolint:gosec
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 2 * time.Second,
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
if err != nil {
return err
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
return err
}
defer session.Close()
// Set IO
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
// Set up terminal modes
// https://net-ssh.github.io/net-ssh/classes/Net/SSH/Connection/Term.html
// https://www.ietf.org/rfc/rfc4254.txt
// https://godoc.org/golang.org/x/crypto/ssh
// THIS IS THE TITLE
// https://pythonhosted.org/ANSIColors-balises/ANSIColors.html
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 115200, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 115200, // output speed = 14.4kbaud
}
fileDescriptor := int(os.Stdin.Fd())
if term.IsTerminal(fileDescriptor) {
originalState, err := term.MakeRaw(fileDescriptor)
if err != nil {
return err
}
defer func() {
err = term.Restore(fileDescriptor, originalState)
if err != nil {
fmt.Printf("error restoring ssh terminal:%v\n", err)
}
}()
termWidth, termHeight, err := term.GetSize(fileDescriptor)
if err != nil {
return err
}
err = session.RequestPty("xterm-256color", termHeight, termWidth, modes)
if err != nil {
return err
}
}
err = session.Shell()
if err != nil {
return err
}
// You should now be connected via SSH with a fully-interactive terminal
// This call blocks until the user exits the session (e.g. via CTRL + D)
return session.Wait()
}
func publicKey(path string) (ssh.AuthMethod, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, err
}
return ssh.PublicKeys(signer), nil
}