forked from zachlatta/sshtron
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
131 lines (110 loc) · 2.85 KB
/
main.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"fmt"
"golang.org/x/crypto/ssh"
"io/ioutil"
"net"
"net/http"
"os"
)
const (
sshPortEnv = "SSH_PORT"
httpPortEnv = "PORT"
defaultSshPort = "2022"
defaultHttpPort = "3000"
)
func handler(conn net.Conn, gm *GameManager, config *ssh.ServerConfig) {
// Before use, a handshake must be performed on the incoming
// net.Conn.
sshConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
fmt.Println("Failed to handshake with new client")
return
}
// The incoming Request channel must be serviced.
go ssh.DiscardRequests(reqs)
// Service the incoming Channel channel.
for newChannel := range chans {
// Channels have a type, depending on the application level
// protocol intended. In the case of a shell, the type is
// "session" and ServerShell may be used to present a simple
// terminal interface.
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
fmt.Println("could not accept channel.")
return
}
// TODO: Remove this -- only temporary while we launch on HN
//
// To see how many concurrent users are online
fmt.Printf("Player joined. Current stats: %d users, %d games\n",
gm.SessionCount(), gm.GameCount())
// Reject all out of band requests accept for the unix defaults, pty-req and
// shell.
go func(in <-chan *ssh.Request) {
for req := range in {
switch req.Type {
case "pty-req":
req.Reply(true, nil)
continue
case "shell":
req.Reply(true, nil)
continue
}
req.Reply(false, nil)
}
}(requests)
gm.HandleNewChannel(channel, sshConn.User())
}
}
func port(env, def string) string {
port := os.Getenv(env)
if port == "" {
port = def
}
return fmt.Sprintf(":%s", port)
}
func main() {
sshPort := port(sshPortEnv, defaultSshPort)
httpPort := port(httpPortEnv, defaultHttpPort)
// Everyone can login!
config := &ssh.ServerConfig{
NoClientAuth: true,
}
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
panic("Failed to load private key")
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
panic("Failed to parse private key")
}
config.AddHostKey(private)
// Create the GameManager
gm := NewGameManager()
fmt.Printf(
"Listening on port %s for SSH and port %s for HTTP...\n",
sshPort,
httpPort,
)
go func() {
panic(http.ListenAndServe(httpPort, http.FileServer(http.Dir("./static/"))))
}()
// Once a ServerConfig has been configured, connections can be
// accepted.
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0%s", sshPort))
if err != nil {
panic("failed to listen for connection")
}
for {
nConn, err := listener.Accept()
if err != nil {
panic("failed to accept incoming connection")
}
go handler(nConn, gm, config)
}
}