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/gabriel-vasile/mimetype v0.1.4
|
||||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.0
|
github.com/gbrlsnchs/jwt/v3 v3.0.0-rc.0
|
||||||
github.com/gogo/protobuf v1.2.1 // indirect
|
github.com/gogo/protobuf v1.2.1 // indirect
|
||||||
|
github.com/google/uuid v1.1.1
|
||||||
github.com/gorilla/websocket v1.4.0
|
github.com/gorilla/websocket v1.4.0
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
||||||
github.com/julienschmidt/httprouter v1.2.0
|
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 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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/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 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
|
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
|
||||||
|
|
57
websocket.go
57
websocket.go
|
@ -3,7 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/gbrlsnchs/jwt/v3"
|
"github.com/gbrlsnchs/jwt/v3"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
|
@ -19,9 +21,11 @@ import (
|
||||||
const (
|
const (
|
||||||
TokenExpiringEvent = "token expiring"
|
TokenExpiringEvent = "token expiring"
|
||||||
TokenExpiredEvent = "token expired"
|
TokenExpiredEvent = "token expired"
|
||||||
|
AuthenticationEvent = "auth"
|
||||||
SetStateEvent = "set state"
|
SetStateEvent = "set state"
|
||||||
SendServerLogsEvent = "send logs"
|
SendServerLogsEvent = "send logs"
|
||||||
SendCommandEvent = "send command"
|
SendCommandEvent = "send command"
|
||||||
|
ErrorEvent = "daemon error"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsocketMessage struct {
|
type WebsocketMessage struct {
|
||||||
|
@ -60,6 +64,7 @@ const (
|
||||||
PermissionConnect = "connect"
|
PermissionConnect = "connect"
|
||||||
PermissionSendCommand = "send-command"
|
PermissionSendCommand = "send-command"
|
||||||
PermissionSendPower = "send-power"
|
PermissionSendPower = "send-power"
|
||||||
|
PermissionReceiveErrors = "receive-errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checks if the given token payload has a permission string.
|
// 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 {
|
if err := handler.HandleInbound(j); err != nil {
|
||||||
zap.S().Warnw("error handling inbound websocket request", zap.Error(err))
|
handler.SendErrorJson(err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,6 +268,38 @@ func (wsh *WebsocketHandler) SendJson(v interface{}) error {
|
||||||
return wsh.Connection.WriteJSON(v)
|
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.
|
// Handle the inbound socket request and route it to the proper server action.
|
||||||
func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
||||||
if !m.inbound {
|
if !m.inbound {
|
||||||
|
@ -277,6 +313,19 @@ func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch m.Event {
|
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:
|
case SetStateEvent:
|
||||||
{
|
{
|
||||||
if !wsh.JWT.HasPermission(PermissionSendPower) {
|
if !wsh.JWT.HasPermission(PermissionSendPower) {
|
||||||
|
@ -328,6 +377,10 @@ func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wsh.Server.State == server.ProcessOfflineState {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return wsh.Server.Environment.SendCommand(strings.Join(m.Args, ""))
|
return wsh.Server.Environment.SendCommand(strings.Join(m.Args, ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user