Compare commits

...

8 Commits

Author SHA1 Message Date
Dane Everitt
96256ac63e [security] fix vulnerability when handling remote file redirects
Also adds the ability for an admin to just completely disable this service if it is not needed on the node.
2021-01-09 17:52:27 -08:00
Dane Everitt
6701aa6dc1 Merge branch 'dane/self-upgrade' into develop 2021-01-09 17:38:18 -08:00
Dane Everitt
ff8926bba8 bye bye command 2021-01-09 17:37:58 -08:00
Dane Everitt
217ca72eb3 Merge pull request #85 from pterodactyl/schrej/formatting
organize imports with gopls format
2021-01-09 17:31:46 -08:00
Jakob Schrettenbrunner
648072436f organize imports with gopls format 2021-01-10 01:22:39 +00:00
Dane Everitt
6fe2468a5a foundation for self-upgrade logic 2021-01-08 22:49:19 -08:00
Dane Everitt
948d927eb9 Cleanup command running a bit 2021-01-08 22:19:23 -08:00
Dane Everitt
b2eaa3f7f8 Update CHANGELOG.md 2021-01-08 21:31:06 -08:00
53 changed files with 279 additions and 183 deletions

View File

@@ -1,9 +1,19 @@
# Changelog # Changelog
## v1.2.3
### Fixed
* **[Security]** Fixes a remaining security vulnerability in the code handling remote file downloads for servers relating to redirect validation.
### Added
* Adds a configuration key at `api.disable_remote_download` that can be set to `true` to completely download the remote download system.
## v1.2.2 ## v1.2.2
### Fixed ### Fixed
* Reverts changes to logic handling blocking until a server process is done running when polling stats. This change exposed a bug in the underlying Docker system causing servers to enter a state in which Wings was unable to terminate the process and Docker commands would hang if executed against the container. * Reverts changes to logic handling blocking until a server process is done running when polling stats. This change exposed a bug in the underlying Docker system causing servers to enter a state in which Wings was unable to terminate the process and Docker commands would hang if executed against the container.
### Changed
* Adds logic to handle a console stream unexpectedly returning an EOF when reading console logs. New code should automatically re-attach the stream avoiding issues where the console would stop live updating for servers.
## v1.2.1 ## v1.2.1
### Fixed ### Fixed
* Fixes servers not be properly marked as no longer transfering if an error occurs during the archive process. * Fixes servers not be properly marked as no longer transfering if an error occurs during the archive process.

View File

@@ -2,17 +2,18 @@ package api
import ( import (
"bytes" "bytes"
"emperror.dev/errors"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/apex/log"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/system"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time" "time"
"emperror.dev/errors"
"github.com/apex/log"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/system"
) )
// Initializes the requester instance. // Initializes the requester instance.

View File

@@ -2,10 +2,11 @@ package api
import ( import (
"encoding/json" "encoding/json"
"github.com/apex/log"
"github.com/pterodactyl/wings/parser"
"regexp" "regexp"
"strings" "strings"
"github.com/apex/log"
"github.com/pterodactyl/wings/parser"
) )
type OutputLineMatcher struct { type OutputLineMatcher struct {

View File

@@ -4,11 +4,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"sync"
"github.com/apex/log" "github.com/apex/log"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"strconv"
"sync"
) )
const ( const (

View File

@@ -1,9 +1,10 @@
package api package api
import ( import (
"regexp"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"regexp"
) )
type SftpAuthRequest struct { type SftpAuthRequest struct {

View File

@@ -1,9 +1,10 @@
package cmd package cmd
import ( import (
"github.com/pterodactyl/wings/config"
"os" "os"
"path/filepath" "path/filepath"
"github.com/pterodactyl/wings/config"
) )
// We've gone through a couple of iterations of where the configuration is stored. This // We've gone through a couple of iterations of where the configuration is stored. This

View File

@@ -4,10 +4,6 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/pterodactyl/wings/config"
"github.com/spf13/cobra"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
@@ -15,6 +11,11 @@ import (
"path" "path"
"regexp" "regexp"
"time" "time"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/pterodactyl/wings/config"
"github.com/spf13/cobra"
) )
var ( var (

View File

@@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/pterodactyl/wings/environment"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@@ -16,6 +15,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/pterodactyl/wings/environment"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal" "github.com/AlecAivazis/survey/v2/terminal"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"

View File

@@ -2,8 +2,15 @@ package cmd
import ( import (
"crypto/tls" "crypto/tls"
"emperror.dev/errors"
"fmt" "fmt"
log2 "log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"emperror.dev/errors"
"github.com/NYTimes/logrotate" "github.com/NYTimes/logrotate"
"github.com/apex/log" "github.com/apex/log"
"github.com/apex/log/handlers/multi" "github.com/apex/log/handlers/multi"
@@ -21,47 +28,54 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/crypto/acme" "golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert" "golang.org/x/crypto/acme/autocert"
"net/http"
"os"
"path"
"path/filepath"
"strings"
) )
var ( var (
profiler = "" configPath = config.DefaultLocation
configPath = config.DefaultLocation debug = false
debug = false
useAutomaticTls = false
tlsHostname = ""
showVersion = false
ignoreCertificateErrors = false
) )
var root = &cobra.Command{ var rootCommand = &cobra.Command{
Use: "wings", Use: "wings",
Short: "The wings of the pterodactyl game management panel", Short: "Runs the API server allowing programatic control of game servers for Pterodactyl Panel.",
Long: ``,
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
if useAutomaticTls && len(tlsHostname) == 0 { if tls, _ := cmd.Flags().GetBool("auto-tls"); tls {
fmt.Println("A TLS hostname must be provided when running wings with automatic TLS, e.g.:\n\n ./wings --auto-tls --tls-hostname my.example.com") if host, _ := cmd.Flags().GetString("tls-hostname"); host == "" {
os.Exit(1) fmt.Println("A TLS hostname must be provided when running wings with automatic TLS, e.g.:\n\n ./wings --auto-tls --tls-hostname my.example.com")
os.Exit(1)
}
} }
}, },
Run: rootCmdRun, Run: rootCmdRun,
} }
func init() { var versionCommand = &cobra.Command{
root.PersistentFlags().BoolVar(&showVersion, "version", false, "show the version and exit") Use: "version",
root.PersistentFlags().StringVar(&configPath, "config", config.DefaultLocation, "set the location for the configuration file") Short: "Prints the current executable version and exits.",
root.PersistentFlags().BoolVar(&debug, "debug", false, "pass in order to run wings in debug mode") Run: func(cmd *cobra.Command, _ []string) {
root.PersistentFlags().StringVar(&profiler, "profiler", "", "the profiler to run for this instance") fmt.Printf("wings v%s\nCopyright © 2018 - 2021 Dane Everitt & Contributors\n", system.Version)
root.PersistentFlags().BoolVar(&useAutomaticTls, "auto-tls", false, "pass in order to have wings generate and manage it's own SSL certificates using Let's Encrypt") },
root.PersistentFlags().StringVar(&tlsHostname, "tls-hostname", "", "required with --auto-tls, the FQDN for the generated SSL certificate") }
root.PersistentFlags().BoolVar(&ignoreCertificateErrors, "ignore-certificate-errors", false, "if passed any SSL certificate errors will be ignored by wings")
root.AddCommand(configureCmd) func Execute() {
root.AddCommand(diagnosticsCmd) if err := rootCommand.Execute(); err != nil {
log2.Fatalf("failed to execute command: %s", err)
}
}
func init() {
rootCommand.PersistentFlags().StringVar(&configPath, "config", config.DefaultLocation, "set the location for the configuration file")
rootCommand.PersistentFlags().BoolVar(&debug, "debug", false, "pass in order to run wings in debug mode")
// Flags specifically used when running the API.
rootCommand.Flags().String("profiler", "", "the profiler to run for this instance")
rootCommand.Flags().Bool("auto-tls", false, "pass in order to have wings generate and manage it's own SSL certificates using Let's Encrypt")
rootCommand.Flags().String("tls-hostname", "", "required with --auto-tls, the FQDN for the generated SSL certificate")
rootCommand.Flags().Bool("ignore-certificate-errors", false, "ignore certificate verification errors when executing API calls")
rootCommand.AddCommand(versionCommand)
rootCommand.AddCommand(configureCmd)
rootCommand.AddCommand(diagnosticsCmd)
} }
// Get the configuration path based on the arguments provided. // Get the configuration path based on the arguments provided.
@@ -85,13 +99,8 @@ func readConfiguration() (*config.Configuration, error) {
return config.ReadConfiguration(p) return config.ReadConfiguration(p)
} }
func rootCmdRun(*cobra.Command, []string) { func rootCmdRun(cmd *cobra.Command, _ []string) {
if showVersion { switch cmd.Flag("profiler").Value.String() {
fmt.Println(system.Version)
os.Exit(0)
}
switch profiler {
case "cpu": case "cpu":
defer profile.Start(profile.CPUProfile).Stop() defer profile.Start(profile.CPUProfile).Stop()
case "mem": case "mem":
@@ -117,7 +126,6 @@ func rootCmdRun(*cobra.Command, []string) {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
exitWithConfigurationNotice() exitWithConfigurationNotice()
} }
panic(err) panic(err)
} }
} }
@@ -141,7 +149,7 @@ func rootCmdRun(*cobra.Command, []string) {
log.Debug("running in debug mode") log.Debug("running in debug mode")
} }
if ignoreCertificateErrors { if ok, _ := cmd.Flags().GetBool("ignore-certificate-errors"); ok {
log.Warn("running with --ignore-certificate-errors: TLS certificate host chains and name will not be verified") log.Warn("running with --ignore-certificate-errors: TLS certificate host chains and name will not be verified")
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{ http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
@@ -280,9 +288,15 @@ func rootCmdRun(*cobra.Command, []string) {
log.WithField("error", err).Error("failed to create backup directory") log.WithField("error", err).Error("failed to create backup directory")
} }
autotls, _ := cmd.Flags().GetBool("auto-tls")
tlshostname, _ := cmd.Flags().GetString("tls-hostname")
if autotls && tlshostname == "" {
autotls = false
}
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"use_ssl": c.Api.Ssl.Enabled, "use_ssl": c.Api.Ssl.Enabled,
"use_auto_tls": useAutomaticTls && len(tlsHostname) > 0, "use_auto_tls": autotls,
"host_address": c.Api.Host, "host_address": c.Api.Host,
"host_port": c.Api.Port, "host_port": c.Api.Port,
}).Info("configuring internal webserver") }).Info("configuring internal webserver")
@@ -293,7 +307,6 @@ func rootCmdRun(*cobra.Command, []string) {
s := &http.Server{ s := &http.Server{
Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port), Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port),
Handler: r, Handler: r,
TLSConfig: &tls.Config{ TLSConfig: &tls.Config{
NextProtos: []string{"h2", "http/1.1"}, NextProtos: []string{"h2", "http/1.1"},
// @see https://blog.cloudflare.com/exposing-go-on-the-internet // @see https://blog.cloudflare.com/exposing-go-on-the-internet
@@ -313,14 +326,14 @@ func rootCmdRun(*cobra.Command, []string) {
} }
// Check if the server should run with TLS but using autocert. // Check if the server should run with TLS but using autocert.
if useAutomaticTls && len(tlsHostname) > 0 { if autotls {
m := autocert.Manager{ m := autocert.Manager{
Prompt: autocert.AcceptTOS, Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(path.Join(c.System.RootDirectory, "/.tls-cache")), Cache: autocert.DirCache(path.Join(c.System.RootDirectory, "/.tls-cache")),
HostPolicy: autocert.HostWhitelist(tlsHostname), HostPolicy: autocert.HostWhitelist(tlshostname),
} }
log.WithField("hostname", tlsHostname). log.WithField("hostname", tlshostname).
Info("webserver is now listening with auto-TLS enabled; certificates will be automatically generated by Let's Encrypt") Info("webserver is now listening with auto-TLS enabled; certificates will be automatically generated by Let's Encrypt")
// Hook autocert into the main http server. // Hook autocert into the main http server.
@@ -336,7 +349,7 @@ func rootCmdRun(*cobra.Command, []string) {
// Start the main http server with TLS using autocert. // Start the main http server with TLS using autocert.
if err := s.ListenAndServeTLS("", ""); err != nil { if err := s.ListenAndServeTLS("", ""); err != nil {
log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlsHostname, "error": err}). log.WithFields(log.Fields{"auto_tls": true, "tls_hostname": tlshostname, "error": err}).
Fatal("failed to configure HTTP server using auto-tls") Fatal("failed to configure HTTP server using auto-tls")
} }
@@ -364,11 +377,6 @@ func rootCmdRun(*cobra.Command, []string) {
} }
} }
// Execute calls cobra to handle cli commands
func Execute() error {
return root.Execute()
}
// Configures the global logger for Zap so that we can call it from any location // Configures the global logger for Zap so that we can call it from any location
// in the code without having to pass around a logger instance. // in the code without having to pass around a logger instance.
func configureLogging(logDir string, debug bool) error { func configureLogging(logDir string, debug bool) error {
@@ -379,20 +387,15 @@ func configureLogging(logDir string, debug bool) error {
p := filepath.Join(logDir, "/wings.log") p := filepath.Join(logDir, "/wings.log")
w, err := logrotate.NewFile(p) w, err := logrotate.NewFile(p)
if err != nil { if err != nil {
panic(errors.WithMessage(err, "failed to open process log file")) return err
} }
log.SetLevel(log.InfoLevel)
if debug { if debug {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.InfoLevel)
} }
log.SetHandler(multi.New( log.SetHandler(multi.New(cli.Default, cli.New(w.File, false)))
cli.Default,
cli.New(w.File, false),
))
log.WithField("path", p).Info("writing log files to disk") log.WithField("path", p).Info("writing log files to disk")
return nil return nil

View File

@@ -1,12 +1,7 @@
package config package config
import ( import (
"emperror.dev/errors"
"fmt" "fmt"
"github.com/cobaugh/osrelease"
"github.com/creasty/defaults"
"github.com/gbrlsnchs/jwt/v3"
"gopkg.in/yaml.v2"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@@ -14,6 +9,12 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"emperror.dev/errors"
"github.com/cobaugh/osrelease"
"github.com/creasty/defaults"
"github.com/gbrlsnchs/jwt/v3"
"gopkg.in/yaml.v2"
) )
const DefaultLocation = "/etc/pterodactyl/config.yml" const DefaultLocation = "/etc/pterodactyl/config.yml"
@@ -87,11 +88,16 @@ type ApiConfiguration struct {
// SSL configuration for the daemon. // SSL configuration for the daemon.
Ssl struct { Ssl struct {
Enabled bool `default:"false"` Enabled bool `json:"enabled" yaml:"enabled"`
CertificateFile string `json:"cert" yaml:"cert"` CertificateFile string `json:"cert" yaml:"cert"`
KeyFile string `json:"key" yaml:"key"` KeyFile string `json:"key" yaml:"key"`
} }
// Determines if functionality for allowing remote download of files into server directories
// is enabled on this instance. If set to "true" remote downloads will not be possible for
// servers.
DisableRemoteDownload bool `json:"disable_remote_download" yaml:"disable_remote_download"`
// The maximum size for files uploaded through the Panel in bytes. // The maximum size for files uploaded through the Panel in bytes.
UploadLimit int `default:"100" json:"upload_limit" yaml:"upload_limit"` UploadLimit int `default:"100" json:"upload_limit" yaml:"upload_limit"`
} }

View File

@@ -3,6 +3,7 @@ package config
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
) )

View File

@@ -2,9 +2,7 @@ package config
import ( import (
"context" "context"
"emperror.dev/errors"
"fmt" "fmt"
"github.com/apex/log"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -13,6 +11,9 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"time" "time"
"emperror.dev/errors"
"github.com/apex/log"
) )
// Defines basic system configuration settings. // Defines basic system configuration settings.

View File

@@ -2,9 +2,10 @@ package environment
import ( import (
"fmt" "fmt"
"strconv"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"strconv"
) )
// Defines the allocations available for a given server. When using the Docker environment // Defines the allocations available for a given server. When using the Docker environment

View File

@@ -2,10 +2,11 @@ package environment
import ( import (
"context" "context"
"github.com/apex/log"
"strconv" "strconv"
"sync" "sync"
"github.com/apex/log"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client" "github.com/docker/docker/client"

View File

@@ -1,8 +1,9 @@
package environment package environment
import ( import (
"github.com/pterodactyl/wings/events"
"os" "os"
"github.com/pterodactyl/wings/events"
) )
const ( const (

View File

@@ -2,9 +2,10 @@ package environment
import ( import (
"fmt" "fmt"
"github.com/apex/log"
"math" "math"
"strconv" "strconv"
"github.com/apex/log"
) )
type Mount struct { type Mount struct {

View File

@@ -2,9 +2,10 @@ package events
import ( import (
"encoding/json" "encoding/json"
"github.com/gammazero/workerpool"
"strings" "strings"
"sync" "sync"
"github.com/gammazero/workerpool"
) )
type Event struct { type Event struct {

View File

@@ -1,8 +1,9 @@
package events package events
import ( import (
"github.com/gammazero/workerpool"
"reflect" "reflect"
"github.com/gammazero/workerpool"
) )
type CallbackPool struct { type CallbackPool struct {

1
go.mod
View File

@@ -63,6 +63,7 @@ require (
github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f
github.com/sirupsen/logrus v1.7.0 // indirect github.com/sirupsen/logrus v1.7.0 // indirect
github.com/spf13/cobra v1.1.1 github.com/spf13/cobra v1.1.1
github.com/spf13/pflag v1.0.5
github.com/ugorji/go v1.2.2 // indirect github.com/ugorji/go v1.2.2 // indirect
github.com/ulikunitz/xz v0.5.9 // indirect github.com/ulikunitz/xz v0.5.9 // indirect
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad

View File

@@ -1,8 +1,9 @@
package installer package installer
import ( import (
"emperror.dev/errors"
"encoding/json" "encoding/json"
"emperror.dev/errors"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"

View File

@@ -2,16 +2,17 @@ package parser
import ( import (
"bytes" "bytes"
"emperror.dev/errors"
"github.com/Jeffail/gabs/v2"
"github.com/apex/log"
"github.com/buger/jsonparser"
"github.com/iancoleman/strcase"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"emperror.dev/errors"
"github.com/Jeffail/gabs/v2"
"github.com/apex/log"
"github.com/buger/jsonparser"
"github.com/iancoleman/strcase"
) )
// Regex to match anything that has a value matching the format of {{ config.$1 }} which // Regex to match anything that has a value matching the format of {{ config.$1 }} which

View File

@@ -2,8 +2,14 @@ package parser
import ( import (
"bufio" "bufio"
"emperror.dev/errors"
"encoding/json" "encoding/json"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/beevik/etree" "github.com/beevik/etree"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
@@ -12,11 +18,6 @@ import (
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
) )
// The file parsing options that are available for a server configuration file. // The file parsing options that are available for a server configuration file.

View File

@@ -18,7 +18,22 @@ import (
"time" "time"
) )
var client = &http.Client{Timeout: time.Hour * 12} var client = &http.Client{
Timeout: time.Hour * 12,
// Disallow any redirect on a HTTP call. This is a security requirement: do not modify
// this logic without first ensuring that the new target location IS NOT within the current
// instance's local network.
//
// This specific error response just causes the client to not follow the redirect and
// returns the actual redirect response to the caller. Not perfect, but simple and most
// people won't be using URLs that redirect anyways hopefully?
//
// We'll re-evaluate this down the road if needed.
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
var instance = &Downloader{ var instance = &Downloader{
// Tracks all of the active downloads. // Tracks all of the active downloads.
downloadCache: make(map[string]*Download), downloadCache: make(map[string]*Download),

View File

@@ -1,16 +1,17 @@
package router package router
import ( import (
"emperror.dev/errors"
"fmt" "fmt"
"net/http"
"os"
"strings"
"emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/server/filesystem" "github.com/pterodactyl/wings/server/filesystem"
"net/http"
"os"
"strings"
) )
type RequestError struct { type RequestError struct {

View File

@@ -1,14 +1,15 @@
package router package router
import ( import (
"io"
"net/http"
"strings"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"io"
"net/http"
"strings"
) )
type Middleware struct{} type Middleware struct{}
@@ -119,6 +120,21 @@ func (m *Middleware) ServerExists() gin.HandlerFunc {
} }
} }
// Checks if remote file downloading is enabled on this instance before allowing access
// to the given endpoint.
func (m *Middleware) CheckRemoteDownloadEnabled() gin.HandlerFunc {
disabled := config.Get().Api.DisableRemoteDownload
return func(c *gin.Context) {
if disabled {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"error": "This functionality is not currently enabled on this instance.",
})
return
}
c.Next()
}
}
// Returns the server instance from the gin context. If there is no server set in the // 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 // context (e.g. calling from a controller not protected by ServerExists) this function
// will panic. // will panic.

View File

@@ -88,9 +88,9 @@ func Configure() *gin.Engine {
files.POST("/decompress", postServerDecompressFiles) files.POST("/decompress", postServerDecompressFiles)
files.POST("/chmod", postServerChmodFile) files.POST("/chmod", postServerChmodFile)
files.GET("/pull", getServerPullingFiles) files.GET("/pull", m.CheckRemoteDownloadEnabled(), getServerPullingFiles)
files.POST("/pull", postServerPullRemoteFile) files.POST("/pull", m.CheckRemoteDownloadEnabled(), postServerPullRemoteFile)
files.DELETE("/pull/:download", deleteServerPullRemoteFile) files.DELETE("/pull/:download", m.CheckRemoteDownloadEnabled(), deleteServerPullRemoteFile)
} }
backup := server.Group("/backup") backup := server.Group("/backup")

View File

@@ -3,12 +3,13 @@ package router
import ( import (
"bufio" "bufio"
"errors" "errors"
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server/backup"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
"github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server/backup"
) )
// Handle a download request for a server backup. // Handle a download request for a server backup.

View File

@@ -3,15 +3,16 @@ package router
import ( import (
"bytes" "bytes"
"context" "context"
"net/http"
"os"
"strconv"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/router/downloader" "github.com/pterodactyl/wings/router/downloader"
"github.com/pterodactyl/wings/router/tokens" "github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"net/http"
"os"
"strconv"
) )
type serverProcData struct { type serverProcData struct {

View File

@@ -1,13 +1,14 @@
package router package router
import ( import (
"emperror.dev/errors"
"fmt" "fmt"
"net/http"
"os"
"emperror.dev/errors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/server/backup" "github.com/pterodactyl/wings/server/backup"
"net/http"
"os"
) )
// Backs up a server. // Backs up a server.

View File

@@ -3,10 +3,11 @@ package router
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
ws "github.com/gorilla/websocket" ws "github.com/gorilla/websocket"
"github.com/pterodactyl/wings/router/websocket" "github.com/pterodactyl/wings/router/websocket"
"time"
) )
// Upgrades a connection to a websocket and passes events along between. // Upgrades a connection to a websocket and passes events along between.

View File

@@ -2,14 +2,15 @@ package router
import ( import (
"bytes" "bytes"
"net/http"
"strings"
"github.com/apex/log" "github.com/apex/log"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/installer" "github.com/pterodactyl/wings/installer"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/system" "github.com/pterodactyl/wings/system"
"net/http"
"strings"
) )
// Returns information about the system that wings is running on. // Returns information about the system that wings is running on.

View File

@@ -3,10 +3,19 @@ package router
import ( import (
"bufio" "bufio"
"crypto/sha256" "crypto/sha256"
"emperror.dev/errors"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
"emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
@@ -19,14 +28,6 @@ import (
"github.com/pterodactyl/wings/router/tokens" "github.com/pterodactyl/wings/router/tokens"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"github.com/pterodactyl/wings/system" "github.com/pterodactyl/wings/system"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
) )
// Number of ticks in the progress bar // Number of ticks in the progress bar

View File

@@ -2,15 +2,16 @@ package server
import ( import (
"crypto/sha256" "crypto/sha256"
"emperror.dev/errors"
"encoding/hex" "encoding/hex"
"github.com/mholt/archiver/v3"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server/filesystem"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"emperror.dev/errors"
"github.com/mholt/archiver/v3"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server/filesystem"
) )
// Archiver represents a Server Archiver. // Archiver represents a Server Archiver.

View File

@@ -1,12 +1,13 @@
package server package server
import ( import (
"io/ioutil"
"os"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"
"github.com/pterodactyl/wings/server/backup" "github.com/pterodactyl/wings/server/backup"
"io/ioutil"
"os"
) )
// Notifies the panel of a backup's state and returns an error if one is encountered // Notifies the panel of a backup's state and returns an error if one is encountered

View File

@@ -1,8 +1,9 @@
package server package server
import ( import (
"github.com/gammazero/workerpool"
"runtime" "runtime"
"github.com/gammazero/workerpool"
) )
// Parent function that will update all of the defined configuration files for a server // Parent function that will update all of the defined configuration files for a server

View File

@@ -1,8 +1,9 @@
package server package server
import ( import (
"github.com/pterodactyl/wings/environment"
"sync" "sync"
"github.com/pterodactyl/wings/environment"
) )
type Configuration struct { type Configuration struct {

View File

@@ -2,14 +2,15 @@ package server
import ( import (
"context" "context"
"emperror.dev/errors"
"fmt" "fmt"
"github.com/mitchellh/colorstring"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/system"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"emperror.dev/errors"
"github.com/mitchellh/colorstring"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/system"
) )
var ErrTooMuchConsoleData = errors.New("console is outputting too much data") var ErrTooMuchConsoleData = errors.New("console is outputting too much data")
@@ -114,7 +115,7 @@ func (ct *ConsoleThrottler) Increment(onTrigger func()) error {
func (s *Server) Throttler() *ConsoleThrottler { func (s *Server) Throttler() *ConsoleThrottler {
s.throttleOnce.Do(func() { s.throttleOnce.Do(func() {
s.throttler = &ConsoleThrottler{ s.throttler = &ConsoleThrottler{
isThrottled: system.NewAtomicBool(false), isThrottled: system.NewAtomicBool(false),
ConsoleThrottles: config.Get().Throttles, ConsoleThrottles: config.Get().Throttles,
} }
}) })

View File

@@ -2,11 +2,12 @@ package server
import ( import (
"fmt" "fmt"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment"
) )
type CrashHandler struct { type CrashHandler struct {

View File

@@ -1,8 +1,9 @@
package server package server
import ( import (
"github.com/pterodactyl/wings/server/filesystem"
"os" "os"
"github.com/pterodactyl/wings/server/filesystem"
) )
func (s *Server) Filesystem() *filesystem.Filesystem { func (s *Server) Filesystem() *filesystem.Filesystem {

View File

@@ -4,6 +4,13 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"html/template"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@@ -14,12 +21,6 @@ import (
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/system" "github.com/pterodactyl/wings/system"
"html/template"
"io"
"os"
"path/filepath"
"strconv"
"strings"
) )
// Executes the installation stack for a server process. Bubbles any errors up to the calling // Executes the installation stack for a server process. Bubbles any errors up to the calling

View File

@@ -2,14 +2,15 @@ package server
import ( import (
"encoding/json" "encoding/json"
"regexp"
"strconv"
"sync"
"github.com/apex/log" "github.com/apex/log"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/events" "github.com/pterodactyl/wings/events"
"regexp"
"strconv"
"sync"
) )
var dockerEvents = []string{ var dockerEvents = []string{

View File

@@ -1,9 +1,14 @@
package server package server
import ( import (
"emperror.dev/errors"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"path/filepath"
"runtime"
"time"
"emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/gammazero/workerpool" "github.com/gammazero/workerpool"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"
@@ -11,10 +16,6 @@ import (
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/environment/docker" "github.com/pterodactyl/wings/environment/docker"
"github.com/pterodactyl/wings/server/filesystem" "github.com/pterodactyl/wings/server/filesystem"
"os"
"path/filepath"
"runtime"
"time"
) )
var servers = NewCollection(nil) var servers = NewCollection(nil)

View File

@@ -1,11 +1,12 @@
package server package server
import ( import (
"path/filepath"
"strings"
"github.com/apex/log" "github.com/apex/log"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"
"path/filepath"
"strings"
) )
// To avoid confusion when working with mounts, assume that a server.Mount has not been properly // To avoid confusion when working with mounts, assume that a server.Mount has not been properly

View File

@@ -2,12 +2,13 @@ package server
import ( import (
"context" "context"
"os"
"time"
"emperror.dev/errors" "emperror.dev/errors"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"
"golang.org/x/sync/semaphore" "golang.org/x/sync/semaphore"
"os"
"time"
) )
type PowerAction string type PowerAction string

View File

@@ -1,10 +1,11 @@
package server package server
import ( import (
"github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/system"
"sync" "sync"
"sync/atomic" "sync/atomic"
"github.com/pterodactyl/wings/environment"
"github.com/pterodactyl/wings/system"
) )
// Defines the current resource usage for a given server instance. If a server is offline you // Defines the current resource usage for a given server instance. If a server is offline you

View File

@@ -2,8 +2,11 @@ package server
import ( import (
"context" "context"
"emperror.dev/errors"
"fmt" "fmt"
"strings"
"sync"
"emperror.dev/errors"
"github.com/apex/log" "github.com/apex/log"
"github.com/creasty/defaults" "github.com/creasty/defaults"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"
@@ -14,8 +17,6 @@ import (
"github.com/pterodactyl/wings/server/filesystem" "github.com/pterodactyl/wings/server/filesystem"
"github.com/pterodactyl/wings/system" "github.com/pterodactyl/wings/system"
"golang.org/x/sync/semaphore" "golang.org/x/sync/semaphore"
"strings"
"sync"
) )
// High level definition for a server instance being controlled by Wings. // High level definition for a server instance being controlled by Wings.

View File

@@ -2,12 +2,13 @@ package server
import ( import (
"encoding/json" "encoding/json"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"sync" "sync"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/environment"
) )
var stateMutex sync.Mutex var stateMutex sync.Mutex

View File

@@ -1,8 +1,9 @@
package server package server
import ( import (
"emperror.dev/errors"
"encoding/json" "encoding/json"
"emperror.dev/errors"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
"github.com/imdario/mergo" "github.com/imdario/mergo"
"github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/environment"

View File

@@ -2,8 +2,9 @@ package server
import ( import (
"context" "context"
"github.com/google/uuid"
"sync" "sync"
"github.com/google/uuid"
) )
type WebsocketBag struct { type WebsocketBag struct {

View File

@@ -1,14 +1,15 @@
package sftp package sftp
import ( import (
"github.com/apex/log"
"github.com/patrickmn/go-cache"
"github.com/pkg/sftp"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/apex/log"
"github.com/patrickmn/go-cache"
"github.com/pkg/sftp"
) )
type FileSystem struct { type FileSystem struct {

View File

@@ -6,11 +6,6 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"github.com/apex/log"
"github.com/patrickmn/go-cache"
"github.com/pkg/sftp"
"github.com/pterodactyl/wings/api"
"golang.org/x/crypto/ssh"
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
@@ -18,6 +13,12 @@ import (
"path" "path"
"strings" "strings"
"time" "time"
"github.com/apex/log"
"github.com/patrickmn/go-cache"
"github.com/pkg/sftp"
"github.com/pterodactyl/wings/api"
"golang.org/x/crypto/ssh"
) )
type Settings struct { type Settings struct {

View File

@@ -2,5 +2,5 @@ package system
var ( var (
// The current version of this software. // The current version of this software.
Version = "v0.0.1" Version = "0.0.1"
) )

View File

@@ -1,8 +1,9 @@
package system package system
import ( import (
"github.com/docker/docker/pkg/parsers/kernel"
"runtime" "runtime"
"github.com/docker/docker/pkg/parsers/kernel"
) )
type Information struct { type Information struct {