Skip to content

Commit 7620b84

Browse files
committed
refactor: update Go module versions and enhance SSH client functionality
1 parent cc1ccaf commit 7620b84

3 files changed

Lines changed: 56 additions & 10 deletions

File tree

go.mod

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
module tunn
22

3-
go 1.21
3+
go 1.23.0
4+
5+
toolchain go1.24.4
46

57
require (
68
github.com/spf13/cobra v1.9.1
79
golang.org/x/crypto v0.33.0
10+
golang.org/x/net v0.21.0
811
)
912

1013
require (
1114
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1215
github.com/spf13/pflag v1.0.6 // indirect
13-
golang.org/x/sys v0.30.0 // indirect
16+
golang.org/x/sys v0.32.0 // indirect
17+
golang.org/x/term v0.31.0 // indirect
1418
)

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
88
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
99
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
1010
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
11-
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
12-
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
13-
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
14-
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
11+
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
12+
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
13+
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
14+
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
15+
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
16+
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
1517
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1618
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

pkg/ssh/client.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package ssh
33
import (
44
"fmt"
55
"net"
6+
"os"
7+
"strings"
68
"time"
79

810
"golang.org/x/crypto/ssh"
11+
"golang.org/x/net/html"
912
)
1013

1114
// Client represents an SSH client that can operate over any net.Conn
@@ -31,6 +34,26 @@ func NewOverWebSocket(conn net.Conn, username, password string) *OverWebSocket {
3134
}
3235
}
3336

37+
// stripHTMLTags removes HTML tags from a string and returns plain text.
38+
func stripHTMLTags(htmlStr string) string {
39+
doc, err := html.Parse(strings.NewReader(htmlStr))
40+
if err != nil {
41+
return htmlStr // fallback to original if parsing fails
42+
}
43+
var b strings.Builder
44+
var f func(*html.Node)
45+
f = func(n *html.Node) {
46+
if n.Type == html.TextNode {
47+
b.WriteString(n.Data)
48+
}
49+
for c := n.FirstChild; c != nil; c = c.NextSibling {
50+
f(c)
51+
}
52+
}
53+
f(doc)
54+
return b.String()
55+
}
56+
3457
// StartTransport initializes the SSH client over the WebSocket connection
3558
func (s *OverWebSocket) StartTransport() error {
3659
fmt.Println("→ Starting SSH transport over WebSocket connection...")
@@ -42,27 +65,38 @@ func (s *OverWebSocket) StartTransport() error {
4265
tcpConn.SetKeepAlivePeriod(30 * time.Second)
4366
}
4467

45-
// Clear any previous deadlines
46-
s.conn.SetReadDeadline(time.Time{})
47-
s.conn.SetWriteDeadline(time.Time{})
68+
// Set a deadline for the SSH handshake to avoid hanging
69+
handshakeTimeout := 15 * time.Second
70+
s.conn.SetDeadline(time.Now().Add(handshakeTimeout))
4871

4972
config := &ssh.ClientConfig{
5073
User: s.username,
5174
Auth: []ssh.AuthMethod{
5275
ssh.Password(s.password),
5376
},
5477
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // WARNING: This is insecure for production
55-
Timeout: 15 * time.Second,
78+
Timeout: handshakeTimeout,
79+
BannerCallback: func(message string) error {
80+
plain := stripHTMLTags(message)
81+
fmt.Fprintln(stderrOrStdout(), plain)
82+
return nil
83+
},
5684
}
5785

5886
fmt.Printf("→ Attempting SSH connection with user: %s\n", s.username)
5987

6088
// Create SSH client using the WebSocket connection
6189
sshConn, chans, reqs, err := ssh.NewClientConn(s.conn, "tcp", config)
6290
if err != nil {
91+
if nErr, ok := err.(net.Error); ok && nErr.Timeout() {
92+
return fmt.Errorf("SSH handshake timed out after %v", handshakeTimeout)
93+
}
6394
return fmt.Errorf("failed to create SSH connection: %v", err)
6495
}
6596

97+
// Clear deadline after handshake
98+
s.conn.SetDeadline(time.Time{})
99+
66100
s.sshClient = ssh.NewClient(sshConn, chans, reqs)
67101
fmt.Println("✓ SSH transport established and authenticated.")
68102
return nil
@@ -80,3 +114,9 @@ func (s *OverWebSocket) Close() error {
80114
}
81115
return nil
82116
}
117+
118+
// stderrOrStdout returns stderr if available, otherwise stdout.
119+
func stderrOrStdout() *os.File {
120+
// fallback to stdout if stderr is not available
121+
return os.Stderr
122+
}

0 commit comments

Comments
 (0)