Send errors back over the socket to users depending on permission
This commit is contained in:
parent
71d5b0fe83
commit
640f4b3a98
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
|||
github.com/gabriel-vasile/mimetype v0.1.4
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.0
|
||||
github.com/gogo/protobuf v1.2.1 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -29,6 +29,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
|
||||
|
|
57
websocket.go
57
websocket.go
|
@ -3,7 +3,9 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gbrlsnchs/jwt/v3"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/pterodactyl/wings/config"
|
||||
|
@ -19,9 +21,11 @@ import (
|
|||
const (
|
||||
TokenExpiringEvent = "token expiring"
|
||||
TokenExpiredEvent = "token expired"
|
||||
AuthenticationEvent = "auth"
|
||||
SetStateEvent = "set state"
|
||||
SendServerLogsEvent = "send logs"
|
||||
SendCommandEvent = "send command"
|
||||
ErrorEvent = "daemon error"
|
||||
)
|
||||
|
||||
type WebsocketMessage struct {
|
||||
|
@ -60,6 +64,7 @@ const (
|
|||
PermissionConnect = "connect"
|
||||
PermissionSendCommand = "send-command"
|
||||
PermissionSendPower = "send-power"
|
||||
PermissionReceiveErrors = "receive-errors"
|
||||
)
|
||||
|
||||
// Checks if the given token payload has a permission string.
|
||||
|
@ -248,8 +253,7 @@ func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps http
|
|||
}
|
||||
|
||||
if err := handler.HandleInbound(j); err != nil {
|
||||
zap.S().Warnw("error handling inbound websocket request", zap.Error(err))
|
||||
break
|
||||
handler.SendErrorJson(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,6 +268,38 @@ func (wsh *WebsocketHandler) SendJson(v interface{}) error {
|
|||
return wsh.Connection.WriteJSON(v)
|
||||
}
|
||||
|
||||
// Sends an error back to the connected websocket instance by checking the permissions
|
||||
// of the token. If the user has the "receive-errors" grant we will send back the actual
|
||||
// error message, otherwise we just send back a standard error message.
|
||||
func (wsh *WebsocketHandler) SendErrorJson(err error) error {
|
||||
wsh.Mutex.Lock()
|
||||
defer wsh.Mutex.Unlock()
|
||||
|
||||
message := "an unexpected error was encountered during the websocket lifecycle"
|
||||
if wsh.JWT != nil && wsh.JWT.HasPermission(PermissionReceiveErrors) {
|
||||
message = err.Error()
|
||||
}
|
||||
|
||||
m, u := wsh.GetErrorMessage(message)
|
||||
|
||||
wsm := WebsocketMessage{Event: ErrorEvent}
|
||||
wsm.Args = []string{m}
|
||||
|
||||
zap.S().Warnw("an error was encountered in the websocket process", zap.String("error_identifier", u.String()), zap.Error(err))
|
||||
|
||||
return wsh.Connection.WriteJSON(wsm)
|
||||
}
|
||||
|
||||
// Converts an error message into a more readable representation and returns a UUID
|
||||
// that can be cross-referenced to find the specific error that triggered.
|
||||
func (wsh *WebsocketHandler) GetErrorMessage(msg string) (string, uuid.UUID) {
|
||||
u, _ := uuid.NewRandom()
|
||||
|
||||
m := fmt.Sprintf("Error Event [%s]: %s", u.String(), msg)
|
||||
|
||||
return m, u
|
||||
}
|
||||
|
||||
// Handle the inbound socket request and route it to the proper server action.
|
||||
func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
||||
if !m.inbound {
|
||||
|
@ -277,6 +313,19 @@ func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
|||
}
|
||||
|
||||
switch m.Event {
|
||||
case AuthenticationEvent:
|
||||
{
|
||||
token, err := ParseJWT([]byte(strings.Join(m.Args, "")))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if token.HasPermission(PermissionConnect) {
|
||||
wsh.JWT = token
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
case SetStateEvent:
|
||||
{
|
||||
if !wsh.JWT.HasPermission(PermissionSendPower) {
|
||||
|
@ -328,6 +377,10 @@ func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if wsh.Server.State == server.ProcessOfflineState {
|
||||
return nil
|
||||
}
|
||||
|
||||
return wsh.Server.Environment.SendCommand(strings.Join(m.Args, ""))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user