Merge branch 'develop' into dane/backup-restore

This commit is contained in:
Dane Everitt
2021-01-25 20:32:32 -08:00
28 changed files with 1070 additions and 415 deletions

View File

@@ -6,20 +6,11 @@ import (
"github.com/pterodactyl/wings/server"
)
// GetServer is a helper function to fetch a server out of the servers
// collection stored in memory. This function should not be used in new
// controllers, prefer ExtractServer where possible.
// Deprecated
func GetServer(uuid string) *server.Server {
return server.GetServers().Find(func(s *server.Server) bool {
return uuid == s.Id()
})
}
// ExtractServer returns the server instance from the gin context. If there is
// no server set in the context (e.g. calling from a controller not protected by
// ServerExists) this function will panic.
// Deprecated
// no server set in the context (e.g. calling from a controller not protected
// by ServerExists) this function will panic.
//
// This function is deprecated. Use middleware.ExtractServer.
func ExtractServer(c *gin.Context) *server.Server {
return middleware.ExtractServer(c)
}

View File

@@ -159,6 +159,15 @@ func AttachRequestID() gin.HandlerFunc {
}
}
// AttachServerManager attaches the server manager to the request context which
// allows routes to access the underlying server collection.
func AttachServerManager(m *server.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("manager", m)
c.Next()
}
}
// CaptureAndAbort aborts the request and attaches the provided error to the gin
// context so it can be reported properly. If the error is missing a stacktrace
// at the time it is called the stack will be attached.
@@ -239,9 +248,13 @@ func SetAccessControlHeaders() gin.HandlerFunc {
// the server ID in the fields list.
func ServerExists() gin.HandlerFunc {
return func(c *gin.Context) {
s := server.GetServers().Find(func(s *server.Server) bool {
return c.Param("server") == s.Id()
})
var s *server.Server
if c.Param("server") != "" {
manager := ExtractManager(c)
s = manager.Find(func(s *server.Server) bool {
return c.Param("server") == s.Id()
})
}
if s == nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "The requested resource does not exist on this instance."})
return
@@ -313,3 +326,11 @@ func ExtractServer(c *gin.Context) *server.Server {
}
return v.(*server.Server)
}
// ExtractManager returns the server manager instance set on the request context.
func ExtractManager(c *gin.Context) *server.Manager {
if v, ok := c.Get("manager"); ok {
return v.(*server.Manager)
}
panic("middleware/middleware: cannot extract server manager: not present in context")
}

View File

@@ -4,21 +4,22 @@ import (
"github.com/apex/log"
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/server"
)
// Configure configures the routing infrastructure for this daemon instance.
func Configure() *gin.Engine {
func Configure(m *server.Manager) *gin.Engine {
gin.SetMode("release")
router := gin.New()
router.Use(gin.Recovery())
router.Use(middleware.AttachRequestID(), middleware.CaptureErrors(), middleware.SetAccessControlHeaders())
router.Use(middleware.AttachServerManager(m))
// @todo log this into a different file so you can setup IP blocking for abusive requests and such.
// This should still dump requests in debug mode since it does help with understanding the request
// lifecycle and quickly seeing what was called leading to the logs. However, it isn't feasible to mix
// this output in production and still get meaningful logs from it since they'll likely just be a huge
// spamfest.
router.Use()
router.Use(gin.LoggerWithFormatter(func(params gin.LogFormatterParams) string {
log.WithFields(log.Fields{
"client_ip": params.ClientIP,

View File

@@ -8,20 +8,23 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server/backup"
)
// Handle a download request for a server backup.
func getDownloadBackup(c *gin.Context) {
manager := middleware.ExtractManager(c)
token := tokens.BackupPayload{}
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
NewTrackedError(err).Abort(c)
return
}
s := GetServer(token.ServerUuid)
if s == nil || !token.IsUniqueRequest() {
s, ok := manager.Get(token.ServerUuid)
if !ok || !token.IsUniqueRequest() {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
"error": "The requested resource was not found on this server.",
})
@@ -57,14 +60,15 @@ func getDownloadBackup(c *gin.Context) {
// Handles downloading a specific file for a server.
func getDownloadFile(c *gin.Context) {
manager := middleware.ExtractManager(c)
token := tokens.FilePayload{}
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
NewTrackedError(err).Abort(c)
return
}
s := GetServer(token.ServerUuid)
if s == nil || !token.IsUniqueRequest() {
s, ok := manager.Get(token.ServerUuid)
if !ok || !token.IsUniqueRequest() {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
"error": "The requested resource was not found on this server.",
})

View File

@@ -11,6 +11,7 @@ import (
"github.com/apex/log"
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/downloader"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server"
)
@@ -22,7 +23,7 @@ type serverProcData struct {
// Returns a single server from the collection of servers.
func getServer(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
c.JSON(http.StatusOK, serverProcData{
ResourceUsage: s.Proc(),
@@ -32,7 +33,7 @@ func getServer(c *gin.Context) {
// Returns the logs for a given server instance.
func getServerLogs(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
l, _ := strconv.Atoi(c.DefaultQuery("size", "100"))
if l <= 0 {
@@ -59,7 +60,7 @@ func getServerLogs(c *gin.Context) {
// things are happening, so theres no reason to sit and wait for a request to finish. We'll
// just see over the socket if something isn't working correctly.
func postServerPower(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Action server.PowerAction `json:"action"`
@@ -109,7 +110,7 @@ func postServerPower(c *gin.Context) {
// Sends an array of commands to a running server instance.
func postServerCommands(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
if running, err := s.Environment.IsRunning(); err != nil {
NewServerError(err, s).Abort(c)
@@ -140,7 +141,7 @@ func postServerCommands(c *gin.Context) {
// Updates information about a server internally.
func patchServer(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
buf := bytes.Buffer{}
buf.ReadFrom(c.Request.Body)
@@ -157,7 +158,7 @@ func patchServer(c *gin.Context) {
// Performs a server installation in a background thread.
func postServerInstall(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
go func(serv *server.Server) {
if err := serv.Install(true); err != nil {
@@ -170,7 +171,7 @@ func postServerInstall(c *gin.Context) {
// Reinstalls a server.
func postServerReinstall(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
if s.ExecutingPowerAction() {
c.AbortWithStatusJSON(http.StatusConflict, gin.H{
@@ -190,7 +191,7 @@ func postServerReinstall(c *gin.Context) {
// Deletes a server from the wings daemon and dissociate it's objects.
func deleteServer(c *gin.Context) {
s := ExtractServer(c)
s := middleware.ExtractServer(c)
// Immediately suspend the server to prevent a user from attempting
// to start it while this process is running.
@@ -234,9 +235,8 @@ func deleteServer(c *gin.Context) {
}
}(s.Filesystem().Path())
uuid := s.Id()
server.GetServers().Remove(func(s2 *server.Server) bool {
return s2.Id() == uuid
middleware.ExtractManager(c).Remove(func(server *server.Server) bool {
return server.Id() == s.Id()
})
// Deallocate the reference to this server.

View File

@@ -71,7 +71,7 @@ type renameFile struct {
// Renames (or moves) files for a server.
func putServerRenameFiles(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Root string `json:"root"`
@@ -136,7 +136,7 @@ func putServerRenameFiles(c *gin.Context) {
// Copies a server file.
func postServerCopyFile(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Location string `json:"location"`
@@ -160,7 +160,7 @@ func postServerCopyFile(c *gin.Context) {
// Deletes files from a server.
func postServerDeleteFiles(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Root string `json:"root"`
@@ -205,7 +205,7 @@ func postServerDeleteFiles(c *gin.Context) {
// Writes the contents of the request to a file on a server.
func postServerWriteFile(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
f := c.Query("file")
f = "/" + strings.TrimLeft(f, "/")
@@ -306,7 +306,7 @@ func deleteServerPullRemoteFile(c *gin.Context) {
// Create a directory on a server.
func postServerCreateDirectory(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Name string `json:"name"`
@@ -333,7 +333,7 @@ func postServerCreateDirectory(c *gin.Context) {
}
func postServerCompressFiles(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
RootPath string `json:"root"`
@@ -423,7 +423,7 @@ type chmodFile struct {
var errInvalidFileMode = errors.New("invalid file mode")
func postServerChmodFile(c *gin.Context) {
s := GetServer(c.Param("server"))
s := ExtractServer(c)
var data struct {
Root string `json:"root"`
@@ -487,14 +487,16 @@ func postServerChmodFile(c *gin.Context) {
}
func postServerUploadFiles(c *gin.Context) {
manager := middleware.ExtractManager(c)
token := tokens.UploadPayload{}
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
NewTrackedError(err).Abort(c)
return
}
s := GetServer(token.ServerUuid)
if s == nil || !token.IsUniqueRequest() {
s, ok := manager.Get(token.ServerUuid)
if !ok || !token.IsUniqueRequest() {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
"error": "The requested resource was not found on this server.",
})

View File

@@ -7,12 +7,14 @@ import (
"github.com/gin-gonic/gin"
ws "github.com/gorilla/websocket"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/router/websocket"
)
// Upgrades a connection to a websocket and passes events along between.
func getServerWebsocket(c *gin.Context) {
s := GetServer(c.Param("server"))
manager := middleware.ExtractManager(c)
s, _ := manager.Get(c.Param("server"))
handler, err := websocket.GetHandler(s, c.Writer, c.Request)
if err != nil {
NewServerError(err, s).Abort(c)

View File

@@ -9,7 +9,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/installer"
"github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/system"
)
@@ -28,7 +28,7 @@ func getSystemInformation(c *gin.Context) {
// Returns all of the servers that are registered and configured correctly on
// this wings instance.
func getAllServers(c *gin.Context) {
c.JSON(http.StatusOK, server.GetServers().All())
c.JSON(http.StatusOK, middleware.ExtractManager(c).All())
}
// Creates a new server on the wings daemon and begins the installation process
@@ -52,7 +52,8 @@ func postCreateServer(c *gin.Context) {
// Plop that server instance onto the request so that it can be referenced in
// requests from here-on out.
server.GetServers().Add(install.Server())
manager := middleware.ExtractManager(c)
manager.Add(install.Server())
// Begin the installation process in the background to not block the request
// cycle. If there are any errors they will be logged and communicated back

View File

@@ -25,6 +25,7 @@ import (
"github.com/pterodactyl/wings/api"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/installer"
"github.com/pterodactyl/wings/router/middleware"
"github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/system"
@@ -323,18 +324,19 @@ func postTransfer(c *gin.Context) {
i.Server().Events().Publish(server.TransferLogsEvent, output)
}
manager := middleware.ExtractManager(c)
// Mark the server as transferring to prevent problems later on during the process and
// then push the server into the global server collection for this instance.
i.Server().SetTransferring(true)
server.GetServers().Add(i.Server())
manager.Add(i.Server())
defer func(s *server.Server) {
// In the event that this transfer call fails, remove the server from the global
// server tracking so that we don't have a dangling instance.
if err := data.sendTransferStatus(!hasError); hasError || err != nil {
sendTransferLog("Server transfer failed, check Wings logs for additional information.")
s.Events().Publish(server.TransferStatusEvent, "failure")
server.GetServers().Remove(func(s2 *server.Server) bool {
return s.Id() == s2.Id()
manager.Remove(func(match *server.Server) bool {
return match.Id() == s.Id()
})
// If the transfer status was successful but the request failed, act like the transfer failed.