Skip to content

Commit 3e7f336

Browse files
committed
feat(ssh): simplify web terminal flow by control messages as JSON requests
All control messages are now sent as JSON requests, including a new message type exclusively for error reporting. WebSocket binary data is now reserved for terminal output, simplifying the protocol and improving separation of concerns.
1 parent 217aa0d commit 3e7f336

File tree

5 files changed

+35
-7
lines changed

5 files changed

+35
-7
lines changed

ssh/web/conn.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ func (c *Conn) WriteMessage(message *Message) (int, error) {
9090
return wrote, nil
9191
}
9292

93+
func (c *Conn) WriteBinary(data []byte) (int, error) {
94+
socket := c.Socket.(*websocket.Conn)
95+
96+
frame, err := socket.NewFrameWriter(websocket.BinaryFrame)
97+
if err != nil {
98+
return 0, errors.Join(ErrConnWriteMessageFailedFrame, err)
99+
}
100+
101+
wrote, err := frame.Write(data)
102+
if err != nil {
103+
return wrote, errors.Join(ErrConnReadMessageSocketWrite, err)
104+
}
105+
106+
return wrote, nil
107+
}
108+
93109
func (c *Conn) Read(buffer []byte) (int, error) {
94110
return c.Socket.Read(buffer)
95111
}

ssh/web/errors.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@ var (
3636
)
3737

3838
var (
39-
ErrConnReadMessageSocketRead = errors.New("failed to read the message from socket")
40-
ErrConnReadMessageSocketWrite = errors.New("failed to write the message's data to socket")
41-
ErrConnReadMessageJSONInvalid = errors.New("failed to parse the message from json")
42-
ErrConnReadMessageKindInvalid = errors.New("this kind of message is invalid")
39+
ErrConnReadMessageSocketRead = errors.New("failed to read the message from socket")
40+
ErrConnReadMessageSocketWrite = errors.New("failed to write the message's data to socket")
41+
ErrConnReadMessageJSONInvalid = errors.New("failed to parse the message from json")
42+
ErrConnReadMessageKindInvalid = errors.New("this kind of message is invalid")
43+
ErrConnWriteMessageFailedFrame = errors.New("failed to create frame")
4344
)
4445

4546
var (

ssh/web/messages.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const (
1111
// messageKindSignature is the identifier to a signature message. This kind of message contains the data to be
1212
// signed by the user's private key.
1313
messageKindSignature
14+
// messageKindError is the identifier to output an erro rmessage. This kind of message contains data to be show
15+
// in terminal for information propose.
16+
messageKindError
1417
)
1518

1619
type Message struct {

ssh/web/session.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func newSession(ctx context.Context, cache cache.Cache, conn *Conn, creds *Crede
264264
return nil
265265
}
266266

267-
func redirToWs(rd io.Reader, ws io.ReadWriter) error {
267+
func redirToWs(rd io.Reader, ws *Conn) error {
268268
var buf [32 * 1024]byte
269269
var start, end, buflen int
270270

@@ -292,7 +292,7 @@ func redirToWs(rd io.Reader, ws io.ReadWriter) error {
292292
}
293293
}
294294

295-
if _, err = ws.Write([]byte(string(bytes.Runes(buf[0:end])))); err != nil {
295+
if _, err = ws.WriteBinary([]byte(string(bytes.Runes(buf[0:end])))); err != nil {
296296
return err
297297
}
298298

ssh/web/web.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/shellhub-io/shellhub/pkg/cache"
1010
"github.com/shellhub-io/shellhub/ssh/pkg/magickey"
1111
"github.com/shellhub-io/shellhub/ssh/web/pkg/token"
12+
log "github.com/sirupsen/logrus"
1213
"golang.org/x/net/websocket"
1314
)
1415

@@ -69,7 +70,14 @@ func NewSSHServerBridge(router *echo.Echo, cache cache.Cache) {
6970

7071
// exit sends the error's message to the client on the browser.
7172
exit := func(wsconn *websocket.Conn, err error) {
72-
wsconn.Write([]byte(err.Error())) //nolint:errcheck
73+
buffer, err := json.Marshal(Message{
74+
Kind: messageKindError,
75+
Data: err.Error(),
76+
})
77+
78+
log.WithError(err).Error("failed to parsing the error message on web terminal")
79+
80+
wsconn.Write(buffer) //nolint:errcheck
7381
}
7482

7583
token, err := getToken(wsconn.Request())

0 commit comments

Comments
 (0)