-
Notifications
You must be signed in to change notification settings - Fork 0
/
shell.go
76 lines (68 loc) · 1.72 KB
/
shell.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
package robin
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/unkaktus/robin/nest"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/term"
)
func kiHandler(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
tokenFilename := strings.TrimSpace(questions[0])
token, err := ioutil.ReadFile(tokenFilename)
if err != nil {
return nil, fmt.Errorf("read token file: %w", err)
}
return []string{string(token)}, nil
}
func Shell(hostname string) error {
config := &gossh.ClientConfig{
HostKeyCallback: gossh.InsecureIgnoreHostKey(),
Auth: []gossh.AuthMethod{
gossh.KeyboardInteractive(kiHandler),
},
}
addr := hostname + ":" + strconv.FormatUint(nest.UserPort(), 10)
conn, err := gossh.Dial("tcp", addr, config)
if err != nil {
return fmt.Errorf("dial ssh: %w", err)
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
return fmt.Errorf("create session: %w", err)
}
defer session.Close()
fd := int(os.Stdin.Fd())
state, err := term.MakeRaw(fd)
if err != nil {
return fmt.Errorf("terminal make raw: %s", err)
}
defer term.Restore(fd, state)
w, h, err := term.GetSize(fd)
if err != nil {
return fmt.Errorf("terminal get size: %s", err)
}
modes := gossh.TerminalModes{
gossh.ECHO: 1,
gossh.TTY_OP_ISPEED: 14400,
gossh.TTY_OP_OSPEED: 14400,
}
term := os.Getenv("TERM")
if term == "" {
term = "xterm-256color"
}
if err := session.RequestPty(term, h, w, modes); err != nil {
return fmt.Errorf("session xterm: %s", err)
}
session.Stdin = os.Stdin
session.Stdout = os.Stdout
session.Stderr = os.Stderr
err = session.Start("")
if err != nil {
return fmt.Errorf("start session: %w", err)
}
return session.Wait()
}